1 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
2 @using System
3 @using Dynamicweb.Rendering
4 @using System.Collections.Generic
5 @using System.Linq
6 @using System.Web
7 @using Dna.Frontend
8 @using Dna.Frontend.Forms
9 @using Dna.Frontend.UI
10 @using Dna.Validation
11 @using Dynamicweb.Content
12 @using Dynamicweb.Core
13 @using Dynamicweb.Forms
14 @using Dynamicweb.Frontend
15 @using Dynamicweb.Security.UserManagement
16 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
17 @using System
18 @using System.Linq
19 @using System.Text
20 @using System.Web
21 @using System.Collections.Generic
22 @using Dna.Frontend
23 @using Dna.Frontend.UI
24 @using Dna.Frontend.Forms
25 @using Dna.UrlServices
26 @using Dna.Validation
27 @using Dynamicweb.Core
28 @using Dynamicweb.Forms
29 @using Dynamicweb.Content
30 @using Dynamicweb.Ecommerce
31 @using Dynamicweb.Rendering
32 @using Dynamicweb.Security.UserManagement
33 @using ImageSettings = Dna.Frontend.UI.ImageSettings
34 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
35 @using System
36 @using System.IO
37 @using System.Web
38 @using System.Linq
39 @using System.Text
40 @using System.Text.RegularExpressions
41 @using System.Collections.Generic
42 @using System.Collections.Specialized
43 @using Dna.Frontend
44 @using Dna.Validation
45 @using Dna.Frontend.UI
46 @using Dna.UrlServices
47 @using Dna.Frontend.Forms
48 @using Dynamicweb.Core
49 @using Dynamicweb.Forms
50 @using Dynamicweb.Rendering
51 @functions{
52
53 #region Url functions
54
55 public string GetCustomerCenterSortUrl(string field, string listType = "Order")
56 {
57 var paragraphId = Pageview.CurrentParagraph.ID.ToString();
58 var sortDirectionParameter = "CCSort" + listType + paragraphId;
59 var sortFieldParameter = "CC" + listType + "ByField" + paragraphId;
60 var sortDirection = Sanitize.Parameter(sortDirectionParameter) == "Desc" || Sanitize.Parameter(sortFieldParameter) != field ? "Asc" : "Desc";
61
62 if (field.IsNotNullOrEmpty())
63 {
64 return "/Default.aspx?Id=" + Pageview.Page.ID + "&" + sortFieldParameter + "=" + field + "&" + sortDirectionParameter + "=" + sortDirection;
65 }
66
67 return string.Empty;
68 }
69
70 public string GetDataListSortUrl(string field)
71 {
72 var paragraphId = Pageview.CurrentParagraph.ID.ToString();
73 var sortDirectionParameter = "sortorder";
74 var sortFieldParameter = "sortby";
75 var sortByParameter = Sanitize.Parameter(sortFieldParameter).IsNotNullOrEmpty() ? Sanitize.Parameter(sortFieldParameter) : string.Empty;
76 var sortOrderParameter = Sanitize.Parameter(sortDirectionParameter).IsNotNullOrEmpty() ? Sanitize.Parameter(sortDirectionParameter) : "ASC";
77 var sortDirection = sortOrderParameter.ToUpper() == "DESC" || sortByParameter != field ? "ASC" : "DESC";
78
79 if (field.IsNotNullOrEmpty())
80 {
81 return "/Default.aspx?Id=" + Pageview.Page.ID + "&" + sortFieldParameter + "=" + field + "&" + sortDirectionParameter + "=" + sortDirection + "&ViewPID=" + paragraphId;
82 }
83 return string.Empty;
84 }
85
86 public string GetSortFieldParameter(string key, string field = "", string listType = "Order")
87 {
88 var paragraphId = Pageview.CurrentParagraph.ID.ToString();
89 if (key.IsNullOrEmpty()) throw new NotSupportedException("'key' is a required field");
90
91 switch (key)
92 {
93 case "name":
94 var parameter = "CC" + listType + "ByField" + paragraphId;
95 return Sanitize.Parameter(parameter);
96 case "value":
97 if (field.IsNullOrEmpty()) return "asc";
98 var sortDirectionParameter = "CCSort" + listType + paragraphId;
99 var sortFieldParameter = "CC" + listType + "ByField" + paragraphId;
100 return Sanitize.Parameter(sortDirectionParameter) == "Desc" || Sanitize.Parameter(sortFieldParameter) != field ? "Asc" : "Desc";
101 default:
102 throw new NotSupportedException(string.Format("The key '{0}' in not supported", key));
103 }
104 }
105
106 #endregion Url functions
107
108 #region Generic functions
109
110 public static string GetAttributes(Dictionary<string, string> attributes)
111 {
112 if (attributes == null || !attributes.Any())
113 {
114 return string.Empty;
115 }
116
117 var attributesConcat = attributes.Aggregate(string.Empty, (current, attribute) => current + GetAttribute(attribute.Key, attribute.Value));
118
119 return attributesConcat;
120 }
121
122 public static string GetAttribute(string attributeName, string attributeValue)
123 {
124 if (attributeValue.IsNullOrEmpty() && !attributeName.Equals("value", StringComparison.InvariantCultureIgnoreCase)) return string.Empty;
125 return " " + attributeName + "=\"" + attributeValue + "\"";
126 }
127
128 #endregion Generic functions
129
130 #region Files functions
131
132 const string ImagesListTitleKey = "title";
133 const string ImagesListImageKey = "image";
134
135 /// <summary>
136 /// Gets the list of files from a folder.
137 /// </summary>
138 /// <return>Item1 is filename (with extension), Item2 is the title and Item3 is the FileType.</return>
139 public static IEnumerable<Tuple<string, string, FileType>> GetFilesInFolder(string defaultFile, string searchPattern, string fileTitle = "", bool addDefaultFile = true)
140 {
141 var files = new List<Tuple<string,string,FileType>>();
142 try
143 {
144 var mapPath = HttpContext.Current.Server.MapPath(defaultFile);
145 var folderServerPath = Path.GetDirectoryName(mapPath);
146
147 if (folderServerPath == null || !Directory.Exists(folderServerPath)) return files;
148
149 // Get Images from folder
150 const string temp = @"\";
151 const string metafield = "title";
152 var metadata = Dynamicweb.Content.Files.Metadata.EditorFactory.GetMetadataForFile(defaultFile);
153 var title = metadata != null && metadata.GetValue(metafield).IsNotNullOrEmpty() ? metadata.GetValue(metafield) : fileTitle;
154 var folderWebPath = defaultFile.Contains("/") ? defaultFile.Substring(0, defaultFile.LastIndexOf("/", StringComparison.Ordinal)) : defaultFile;
155
156 if (addDefaultFile && File.Exists(mapPath))
157 {
158 files.Add(new Tuple<string, string, FileType>(defaultFile, title, defaultFile.GetFileType()));
159 }
160
161 foreach (var file in Directory.GetFiles(folderServerPath, searchPattern))
162 {
163 var filePath = folderWebPath + "/" + file.Substring(file.LastIndexOf(temp, StringComparison.Ordinal) + 1, file.Length - file.LastIndexOf(temp, StringComparison.Ordinal) - 1);
164 metadata = Dynamicweb.Content.Files.Metadata.EditorFactory.GetMetadataForFile(filePath);
165 title = metadata != null && metadata.GetValue(metafield).IsNullOrEmpty() ? metadata.GetValue(metafield) : fileTitle;
166
167 files.Add(new Tuple<string, string, FileType>(filePath, title, file.GetFileType()));
168 }
169 }
170 catch (Exception ex){}
171
172 return files;
173 }
174 /// <summary>
175 /// Gets the list of image or HTML5 video files from a folder.
176 /// </summary>
177 /// <return>Item1 is filename (with extension), Item2 is the title and Item3 is the FileType (Image, Video).</return>
178 public static IEnumerable<Tuple<string,string,FileType>> GetMediaFilesInFolder(string defaulMedia, string searchPattern, string defaultName = "", bool addDefaultMedia = true)
179 {
180 return GetFilesInFolder(defaulMedia, searchPattern, defaultName, addDefaultMedia).Where(f => f.Item3 == FileType.Image || f.Item3 == FileType.Video).ToList();
181 }
182
183 #endregion Files functions
184
185 #region Image functions
186
187 public static Dictionary<string, string> GetWidthAndHeightFromQueryString(string imageSource, bool addSource = false)
188 {
189 var widthAndHeight = new Dictionary<string, string>();
190
191 if(imageSource.Contains("?")){
192 var querySubstring = imageSource.Substring(imageSource.LastIndexOf('?') + 1);
193 var queryParams = HttpUtility.HtmlDecode(querySubstring).Split('&');
194
195 if (!queryParams.Any())
196 return widthAndHeight;
197
198 foreach (var param in queryParams.Where(k => k.StartsWith("width") || k.StartsWith("height")))
199 {
200 var keyValuePair = param.Split('=');
201
202 if (keyValuePair[1].IsNotNullOrEmpty())
203 {
204 widthAndHeight.Add(keyValuePair[0].ToLower(), keyValuePair[1]);
205 }
206 }
207 }
208 else if(imageSource.Contains("width") || imageSource.Contains("height"))
209 {
210 var queryParams = imageSource.Split('/');
211 var imgParam = string.Empty;
212
213 foreach (var param in queryParams)
214 {
215 switch (imgParam)
216 {
217 case "width":
218 widthAndHeight.Add("width", param);
219 break;
220 case "height":
221 widthAndHeight.Add("height", param);
222 break;
223 }
224
225 switch (param)
226 {
227 case "width":
228 imgParam = "width";
229 break;
230 case "height":
231 imgParam = "height";
232 break;
233 default:
234 imgParam = string.Empty;
235 break;
236 }
237 }
238 }
239
240 if (addSource && imageSource.IsNotNullOrEmpty())
241 {
242 widthAndHeight.Add("srcset", imageSource);
243 }
244
245 return widthAndHeight;
246 }
247
248 #endregion Image functions
249
250 #region Form Field functions
251
252 public string GetWrapperStart(bool includeWrapper, FieldType fieldType, string htmlElement, bool isRequired = false, string fieldClass = "")
253 {
254 if (!includeWrapper || htmlElement.IsNullOrEmpty()) return string.Empty;
255 var cssClass = new List<string> {fieldType.ToString().ToLower()};
256
257 if (fieldClass.IsNotNullOrEmpty())
258 cssClass.Add(fieldClass);
259 if (isRequired)
260 cssClass.Add("mandatory");
261
262 var attributes = new Dictionary<string, string>()
263 {
264 {"class", string.Join(" ", cssClass)}
265 };
266
267 return GetHtmlElement(htmlElement, attributes);
268 }
269
270 public string GetWrapperEnd(bool includeWrapper, string htmlElement)
271 {
272 return !includeWrapper ? string.Empty : GetHtmlElement(htmlElement, true);
273 }
274
275 public string GetControlWithRequiredClass(bool isRequired, string control, string fieldClass = "")
276 {
277 if (!isRequired) return control;
278 if (fieldClass.IsNotNullOrEmpty()) fieldClass += " ";
279 fieldClass += "mandatory";
280 var regex = new Regex(Regex.Escape(" "));
281 return regex.Replace(control, " class=\"" + fieldClass + "\" ", 1);
282 }
283
284 public static string GetAttributes(FieldSettings settings, bool returnFieldType = true)
285 {
286 var attributes = new StringBuilder();
287 if (returnFieldType)
288 {
289 var fieldType = string.Empty;
290 switch (settings.Type)
291 {
292 case FieldType.Select:
293 break;
294 case FieldType.Checkboxlist:
295 fieldType = FieldType.Checkbox.ToString().ToLower();
296 break;
297 case FieldType.DatetimeLocal:
298 fieldType = "datetime-local";
299 break;
300 case FieldType.Textarea:
301 case FieldType.File:
302 case FieldType.Text:
303 case FieldType.Hidden:
304 case FieldType.Submit:
305 case FieldType.Reset:
306 case FieldType.Radio:
307 case FieldType.Checkbox:
308 case FieldType.Divider:
309 case FieldType.Image:
310 case FieldType.Password:
311 case FieldType.Textstring:
312 case FieldType.Button:
313 case FieldType.Search:
314 case FieldType.Email:
315 case FieldType.Url:
316 case FieldType.Tel:
317 case FieldType.Number:
318 case FieldType.Range:
319 case FieldType.Date:
320 case FieldType.Month:
321 case FieldType.Week:
322 case FieldType.Time:
323 case FieldType.Datetime:
324 case FieldType.Color:
325 case FieldType.Unknown:
326 default:
327 fieldType = settings.Type.ToString().ToLower();
328 break;
329 }
330 if (!settings.Attributes.ContainsKey("type"))
331 {
332 attributes.Append(GetAttribute("type", fieldType));
333 }
334 }
335 attributes.Append(GetAttribute("class", settings.CssClass));
336 attributes.Append(GetAttribute("id", settings.Id));
337 attributes.Append(GetAttribute("name", settings.SystemName));
338 if (settings.Type != FieldType.Textarea)
339 {
340 attributes.Append(GetAttribute("value", settings.Value));
341 }
342 if (settings.Type == FieldType.Email || settings.Type == FieldType.Password || settings.Type == FieldType.Search || settings.Type == FieldType.Tel || settings.Type == FieldType.Text || settings.Type == FieldType.Url)
343 {
344 // Only works wit these types
345 attributes.Append(GetAttribute("placeholder", settings.Placeholder));
346 }
347 if (settings.Type == FieldType.Datetime)
348 {
349 attributes.Append(GetAttribute("placeholder", "📅"));
350 }
351 if (settings.Type != FieldType.Checkboxlist)
352 {
353 attributes.Append(GetAttribute("required", settings.IsRequired));
354 }
355 attributes.Append(GetAttributes(settings.Attributes));
356 return attributes.ToString();
357 }
358
359 public static string GetAttributes(FieldOption optionSettings, FieldType fieldType = FieldType.Select)
360 {
361 var attributes = new StringBuilder();
362 if (fieldType != FieldType.Select)
363 {
364 attributes.Append(GetAttribute("name", optionSettings.SystemName));
365 }
366 attributes.Append(GetAttribute("value", optionSettings.Value));
367 attributes.Append(GetAttributes(optionSettings.Attributes));
368 return attributes.ToString();
369 }
370
371 public static string GetAttribute(string attributeName, bool attributeValue)
372 {
373 if (!attributeValue) return string.Empty;
374 return " " + attributeName + "=\"" + attributeName + "\"";
375 }
376
377 public static string GetAttributeString(string string1 = "", string string2 = "")
378 {
379 var result = new List<string>();
380
381 if (string1.IsNotNullOrEmpty())
382 result.AddRange(string1.Split(' ').ToList());
383 if (string2.IsNotNullOrEmpty())
384 result.AddRange(string2.Split(' ').ToList());
385
386 return string.Join(" ", result);
387 }
388
389 #endregion
390
391 #region Dynamicweb Template Engine Workaround
392
393 public static string GetHtmlElement(string element, bool isClosingElement = false)
394 {
395 return GetHtmlElementForDw(element, null, string.Empty, isClosingElement);
396 }
397
398 public static string GetHtmlElement(string element, Dictionary<string, string> attributes, bool isClosingElement = false)
399 {
400 return GetHtmlElementForDw(element, attributes, string.Empty, isClosingElement);
401 }
402
403 public static string GetHtmlElement(string element, string processedAttributes, bool isClosingElement = false)
404 {
405 return GetHtmlElementForDw(element, null, processedAttributes, isClosingElement);
406 }
407
408 private static string GetHtmlElementForDw(string element, Dictionary<string, string> attributes = null, string processedAttributes = "", bool isClosingElement = false)
409 {
410 var result = new StringBuilder("<");
411
412 if (attributes != null || processedAttributes.IsNotNullOrEmpty())
413 {
414 result.Append(element);
415 if (attributes != null)
416 {
417 result.Append(GetAttributes(attributes));
418 }
419 else if (processedAttributes.IsNotNullOrEmpty())
420 {
421 result.Append(processedAttributes);
422 }
423 if (isClosingElement)
424 {
425 result.Append("/");
426 }
427 }
428 else
429 {
430 if (isClosingElement)
431 {
432 result.Append("/");
433 }
434 result.Append(element);
435 }
436
437 result.Append(">");
438
439 return result.ToString();
440 }
441
442 #endregion Dynamicweb Template Engine Workaround
443 }
444 @{
445
446 @* Tab helpers *@
447 @helper InternalRenderTabHeader(string key, string label, string cssClass = "")
448 {
449 @SnippetStart("tabHeaders")
450 <li class="@cssClass">
451 <a href="@key">@label</a>
452 </li>
453 @SnippetEnd("tabHeaders")
454 }
455
456
457 @* Paging helpers *@
458 @helper InternalRenderGoToFirstPage(NameValueCollection queryParameters, string pageNumQueryParameter, int currentPage, int numOfPages, int loopPageSize, int currentPageNum = 0)
459 {
460 if (currentPageNum == 0)
461 {
462 currentPageNum = currentPage;
463 }
464
465 if (currentPage > 2 && numOfPages > loopPageSize && currentPageNum != 1)
466 {
467 queryParameters.Remove(pageNumQueryParameter);
468 @InternalRenderPageItem(queryParameters, "1")
469 @InternalRenderEllipsis()
470 }
471 }
472
473 @helper InternalRenderGoToLastPage(NameValueCollection queryParameters, string pageNumQueryParameter, int currentPage, int numOfPages, int loopPageSize, int endPage)
474 {
475 if (currentPage < numOfPages - 1 && numOfPages > loopPageSize && endPage != numOfPages)
476 {
477 queryParameters = Helpers.UpdateQueryStringKeyValue(queryParameters, pageNumQueryParameter, numOfPages.ToString());
478 @InternalRenderEllipsis()
479 @InternalRenderPageItem(queryParameters, numOfPages.ToString())
480 }
481 }
482
483 @helper InternalRenderPageItem(NameValueCollection queryParameters, string pageNum, string cssClass = "")
484 {
485 var url = Helpers.GetCurrentUrl(true, true);
486 var href = Helpers.BuildUri(url, queryParameters);
487
488 <li class="@cssClass">
489 <a href="@href.PathAndQuery">
490 @pageNum
491 </a>
492 </li>
493 }
494
495 @helper InternalRenderPageItem(string href, string label, string cssPartialClass, IconPosition position)
496 {
497 <li>
498 <a href="@href">
499 @RenderIcon(cssPartialClass, label, position)
500 </a>
501 </li>
502 }
503
504 @helper InternalRenderEllipsis()
505 {
506 <li>
507 <span>...</span>
508 </li>
509 }
510
511
512 @* Form field helpers *@
513 @helper InternalRenderLabel(FieldSettings settings)
514 {
515 @InternalRenderLabel(settings.Label, settings.TranslateKeyForLabel)
516 }
517
518 @helper InternalRenderLabel(string label, string translateKey = "")
519 {
520 @( translateKey.IsNotNullOrEmpty() ? Translate(translateKey) : label)
521 }
522
523 @helper InternalRenderCheckboxField(FieldSettings settings)
524 {
525 if (settings.SystemName.IsNotNullOrEmpty() || settings.Control.IsNotNullOrEmpty())
526 {
527 settings.Assert(FieldType.Checkbox);
528 if (settings.IsChecked && !settings.Attributes.ContainsKey("checked"))
529 {
530 settings.Attributes.Add("checked", "checked");
531 }
532
533 @InternalRenderFieldHeader(settings, false)
534
535 if (settings.Label.IsNotNullOrEmpty() || settings.TranslateKeyForLabel.IsNotNullOrEmpty())
536 {
537 var cssClassList = new List<string> {settings.Type.ToString().ToLower(), settings.LabelCssClass};
538 var cssClass = string.Join(" ", cssClassList.Where(s => s.IsNotNullOrEmpty()));
539
540 if (!settings.LabelAttributes.ContainsKey("class"))
541 {
542 settings.LabelAttributes.Add("class", cssClass);
543 }
544 else
545 {
546 settings.LabelAttributes["class"] = string.Concat(cssClass, " ", settings.LabelAttributes["class"]);
547 }
548 if (!settings.LabelAttributes.ContainsKey("for"))
549 {
550 settings.LabelAttributes.Add("for", settings.Id);
551 }
552
553 @GetHtmlElement("label", settings.LabelAttributes)
554 if (settings.Control.IsNotNullOrEmpty())
555 {
556 if (settings.Value.IsNullOrEmpty() && settings.IsRequired)
557 {
558 var checkedAttribute = "checked=\"checked\"";
559 settings.Control = settings.Control.Replace(checkedAttribute, string.Empty);
560 }
561 @settings.Control
562 }
563 else
564 {
565 @GetHtmlElement("input", GetAttributes(settings), true)
566 }
567 <span>
568 @InternalRenderLabel(settings)
569 </span>
570 @GetHtmlElement("label", true)
571 }
572 else
573 {
574 if (settings.Control.IsNotNullOrEmpty())
575 {
576 if (settings.Value.IsNullOrEmpty() && settings.IsRequired)
577 {
578 var checkedAttribute = "checked=\"checked\"";
579 settings.Control = settings.Control.Replace(checkedAttribute, string.Empty);
580 }
581 @settings.Control
582 }
583 else
584 {
585 @GetHtmlElement("input", GetAttributes(settings), true)
586 }
587 }
588
589 @InternalRenderFieldFooter(settings)
590 }
591 }
592
593 @helper InternalRenderTextareaField(FieldSettings settings)
594 {
595 if (settings.SystemName.IsNotNullOrEmpty() || settings.Control.IsNotNullOrEmpty())
596 {
597 settings.Assert(FieldType.Textarea);
598
599 @InternalRenderFieldHeader(settings)
600
601 if (settings.Control.IsNotNullOrEmpty())
602 {
603 @GetControlWithRequiredClass(settings.IsRequired, settings.Control)
604 }
605 else
606 {
607 if (!settings.Attributes.ContainsKey("rows"))
608 {
609 settings.Attributes.Add("rows", "6");
610 }
611 if (!settings.Attributes.ContainsKey("cols"))
612 {
613 settings.Attributes.Add("cols", "50");
614 }
615 @GetHtmlElement("textarea", GetAttributes(settings, false))
616 @settings.Value
617 @GetHtmlElement("textarea", true)
618 }
619
620 @InternalRenderFieldFooter(settings)
621 }
622 }
623
624 @helper InternalRenderRadioOrCheckboxListField(FieldSettings settings)
625 {
626 if (settings.LoopOptions.Any() || settings.FieldOptionsList.Any() || settings.Control.IsNotNullOrEmpty())
627 {
628 var optionCount = 0;
629
630 settings.Assert(FieldType.Radio);
631
632 @InternalRenderFieldHeader(settings)
633
634 if (settings.LoopOptions.Any())
635 {
636 settings.CssClass = settings.Type.ToString().ToLower();
637 foreach (var option in settings.LoopOptions)
638 {
639 optionCount++;
640 if (settings.Id.IsNullOrEmpty() || settings.Id == settings.SystemName)
641 {
642 settings.Id = settings.SystemName + optionCount;
643 }
644
645 var cssClassList = new List<string> {settings.Type.ToString().ToLower(), settings.CssClass};
646 var cssClass = string.Join(" ", cssClassList.Where(s => s.IsNotNullOrEmpty()));
647
648 if (!settings.LabelAttributes.ContainsKey("class"))
649 {
650 settings.LabelAttributes.Add("class", cssClass);
651 }
652 else
653 {
654 settings.LabelAttributes["class"] = string.Concat(cssClass, " ", settings.LabelAttributes["class"]);
655 }
656 if (!settings.LabelAttributes.ContainsKey("for"))
657 {
658 settings.LabelAttributes.Add("for", settings.Id);
659 }
660
661 @GetHtmlElement("label", settings.LabelAttributes)
662 @GetHtmlElement("input", GetAttributes(settings), true)
663 <span>@option.GetString(settings.LabelLoopTag)</span>
664 @GetHtmlElement("label", true)
665 }
666 }
667 else if (settings.FieldOptionsList.Any())
668 {
669 foreach (var option in settings.FieldOptionsList)
670 {
671 optionCount++;
672
673 if (option.SystemName.IsNullOrEmpty())
674 {
675 option.SystemName = settings.SystemName;
676 }
677 if (option.Id.IsNullOrEmpty() || option.Id == option.SystemName)
678 {
679 option.Id = option.SystemName + optionCount;
680 }
681 var cssClassList = new List<string> {settings.Type.ToString().ToLower(), option.CssClass};
682 var cssClass = string.Join(" ", cssClassList.Where(s => s.IsNotNullOrEmpty()));
683
684 if (!option.LabelAttributes.ContainsKey("class"))
685 {
686 option.LabelAttributes.Add("class", cssClass);
687 }
688 else
689 {
690 option.LabelAttributes["class"] = string.Concat(cssClass, " ", option.LabelAttributes["class"]);
691 }
692 if (!option.LabelAttributes.ContainsKey("for"))
693 {
694 option.LabelAttributes.Add("for", option.Id);
695 }
696
697 @GetHtmlElement("label", option.LabelAttributes)
698 @InternalRenderInputOptionField("input", option, settings.Type)
699 <span>@option.Label</span>
700 @GetHtmlElement("label", true)
701 }
702 }
703 else if (settings.Control.IsNotNullOrEmpty())
704 {
705 @settings.Control
706 }
707
708 @InternalRenderFieldFooter(settings)
709 }
710 }
711
712 @helper InternalRenderInputField(FieldSettings settings)
713 {
714 if (settings.SystemName.IsNotNullOrEmpty() || settings.Control.IsNotNullOrEmpty())
715 {
716 settings.Assert(FieldType.Text);
717
718 @InternalRenderFieldHeader(settings)
719
720 if (settings.Control.IsNotNullOrEmpty())
721 {
722 var type = settings.Type.ToString().ToLower();
723 if (settings.Type == FieldType.DatetimeLocal)
724 {
725 type = "datetime-local";
726 }
727
728 if (settings.Type == FieldType.Password)
729 {
730 settings.Control = settings.Control.Replace("input ", "input autocomplete=\"off\" ");
731 }
732 @GetControlWithRequiredClass(settings.IsRequired, settings.Control)
733 }
734 else
735 {
736 if (settings.Type == FieldType.Password && !settings.Attributes.ContainsKey("autocomplete"))
737 {
738 settings.Attributes.Add("autocomplete", "off");
739 }
740 @GetHtmlElement("input", GetAttributes(settings), true)
741 }
742
743 @InternalRenderFieldFooter(settings)
744 }
745 }
746
747 @helper InternalRenderDateTimeField(FieldSettings settings)
748 {
749 if (settings.SystemName.IsNotNullOrEmpty() || settings.Control.IsNotNullOrEmpty())
750 {
751 settings.Assert(FieldType.Datetime);
752 settings.Attributes = new Dictionary<string, string>
753 {
754 {"placeholder", ""}
755 };
756
757 @InternalRenderFieldHeader(settings)
758
759 if (settings.Control.IsNotNullOrEmpty())
760 {
761 var type = settings.Type.ToString().ToLower();
762
763 settings.Control = settings.Control.Replace("type=\"text\"", "type=\"" + type + "\"");
764 @GetControlWithRequiredClass(settings.IsRequired, settings.Control)
765 }
766 else
767 {
768 @GetHtmlElement("input", GetAttributes(settings), true)
769 }
770
771 @InternalRenderFieldFooter(settings)
772 }
773 }
774
775 @helper InternalRenderSelectField(FieldSettings settings)
776 {
777 const int limit = 10;
778
779 settings.Assert(FieldType.Select);
780
781 if (settings.CssClass.ToLower().Contains("country"))
782 {
783 @RenderCountriesDropdownField(settings, true, settings.CssClass.ToLower().Contains("highlights"))
784 }
785 else
786 {
787 if (settings.SystemName.IsNotNullOrEmpty() || settings.Control.IsNotNullOrEmpty() || settings.FieldOptionsList.Any() || settings.ValuesList.Any())
788 {
789 @InternalRenderFieldHeader(settings)
790
791 int optionsCount;
792 if (settings.Control.IsNotNullOrEmpty())
793 {
794 optionsCount = Regex.Matches(settings.Control, "option ").Count;
795
796 if (optionsCount > limit || optionsCount == 0)
797 {
798 settings.Control = settings.Control.Replace("select ", "select data-live-search=\"true\" ");
799 }
800 @GetControlWithRequiredClass(settings.IsRequired, settings.Control, settings.CssClass)
801 }
802 else
803 {
804 optionsCount = settings.FieldOptionsList.Count + settings.ValuesList.Count;
805
806 if (!settings.Attributes.ContainsKey("multiple") && !settings.Attributes.ContainsKey("data-live-search") && (optionsCount > limit || optionsCount == 0))
807 {
808 settings.Attributes.Add("data-live-search", "true");
809 }
810 @GetHtmlElement("select", GetAttributes(settings, false))
811
812 if (settings.FirstHardcodedOptionLabel.IsNotNullOrEmpty())
813 {
814 @InternalRenderOption(FieldOption.CreateOption(settings.FirstHardcodedOptionLabel, settings.FirstHardcodedOptionValue, settings.IsFirstHardcodedOptionSelected))
815 }
816
817 foreach (var option in settings.FieldOptionsList)
818 {
819 @InternalRenderOption(option)
820 }
821 foreach (var option in settings.ValuesList)
822 {
823 @InternalRenderOption(FieldOption.CreateOption(option, option))
824 }
825
826 @GetHtmlElement("select", true)
827 }
828
829 @InternalRenderFieldFooter(settings)
830 }
831 }
832 }
833
834 @helper InternalRenderButtonField(FieldSettings settings)
835 {
836 settings.Assert(FieldType.Button);
837
838 @InternalRenderFieldHeader(settings, false)
839
840 if (settings.Control.IsNotNullOrEmpty())
841 {
842 var controlOutput = settings.Control;
843 switch (settings.Type)
844 {
845 case FieldType.Submit:
846 controlOutput = controlOutput.Replace("input ", "input class='btn btn-default'");
847 break;
848 case FieldType.Reset:
849 controlOutput = controlOutput.Replace("input ", "input class='btn btn-bg2'");
850 break;
851 case FieldType.Button:
852 case FieldType.Textarea:
853 case FieldType.File:
854 case FieldType.Text:
855 case FieldType.Hidden:
856 case FieldType.Radio:
857 case FieldType.Checkbox:
858 case FieldType.Select:
859 case FieldType.Checkboxlist:
860 case FieldType.Divider:
861 case FieldType.Image:
862 case FieldType.Password:
863 case FieldType.Textstring:
864 case FieldType.Search:
865 case FieldType.Email:
866 case FieldType.Url:
867 case FieldType.Tel:
868 case FieldType.Number:
869 case FieldType.Range:
870 case FieldType.Date:
871 case FieldType.Month:
872 case FieldType.Week:
873 case FieldType.Time:
874 case FieldType.Datetime:
875 case FieldType.DatetimeLocal:
876 case FieldType.Color:
877 case FieldType.Unknown:
878 default:
879 throw new NotSupportedException(string.Format("Unsupported Field Type: {0}.", settings.Type.ToString()));
880 }
881 @controlOutput
882 }
883 else
884 {
885 settings.CssClass = settings.CssClass.IsNullOrEmpty() ? "btn btn-default" : "btn " + settings.CssClass;
886 if (settings.Type == FieldType.Button)
887 {
888 if (settings.Label.IsNullOrEmpty())
889 {
890 settings.Label = Translate("Button");
891 }
892 @GetHtmlElement("button", GetAttributes(settings))
893 @InternalRenderLabel(settings)
894 @GetHtmlElement("button", true)
895 }
896 else
897 {
898 @GetHtmlElement("input", GetAttributes(settings), true)
899 }
900 }
901
902 @InternalRenderFieldFooter(settings)
903 }
904
905
906 @* Forms for Editors field types in enum FieldType *@
907 @helper InternalRenderTextStringField(FieldSettings settings)
908 {
909 settings.Assert(FieldType.Textstring);
910
911 if (settings.Description.IsNotNullOrEmpty() || settings.Control.IsNotNullOrEmpty())
912 {
913 if (settings.Control.IsNotNullOrEmpty())
914 {
915 @settings.Control
916 }
917 else
918 {
919 <p class="help-block">@settings.Description</p>
920 }
921 }
922 }
923
924 @helper InternalRenderImageField(FieldSettings settings)
925 {
926 settings.Assert(FieldType.Image);
927
928 if (settings.Control.IsNotNullOrEmpty())
929 {
930 @settings.Control
931 }
932 }
933
934 @helper InternalRenderDividerField(FieldSettings settings)
935 {
936 settings.Assert(FieldType.Divider);
937
938 <hr class="divider" />
939 }
940
941 @helper InternalRenderInputOptionField(string htmlElement, FieldOption optionSettings, FieldType type = FieldType.Radio)
942 {
943 var fieldType = type == FieldType.Checkboxlist ? FieldType.Checkbox.ToString().ToLower() : type.ToString().ToLower();
944 var attributes = new StringBuilder(GetAttribute("type", fieldType));
945 attributes.Append(GetAttribute("value", optionSettings.Value));
946 attributes.Append(GetAttribute("name", optionSettings.SystemName));
947 attributes.Append(optionSettings.Id.IsNotNullOrEmpty() ? GetAttribute("id", optionSettings.Id) : optionSettings.SystemName);
948 attributes.Append(GetAttributes(optionSettings.Attributes));
949
950 if (optionSettings.IsSelected)
951 {
952 attributes.Append(GetAttribute("checked", "checked"));
953 }
954 if (optionSettings.IsDisabled)
955 {
956 attributes.Append(GetAttribute("disabled", "disabled"));
957 }
958
959 @GetHtmlElement(htmlElement, attributes.ToString())
960 }
961
962 @helper InternalRenderOption(FieldOption optionSettings)
963 {
964 var selected = optionSettings.IsSelected ? " selected" : string.Empty;
965 var disabled = optionSettings.IsDisabled ? " disabled" : string.Empty;
966 var readOnly = optionSettings.IsReadOnly ? " readonly" : string.Empty;
967 var attributes = GetAttributes(optionSettings);
968
969 @GetHtmlElement("option", attributes + selected + disabled + readOnly)
970 @InternalRenderLabel(optionSettings.Label, optionSettings.TranslateKeyForLabel)
971 @GetHtmlElement("option", true)
972 }
973
974 @helper InternalRenderFieldHeader(FieldSettings settings, bool renderLabel = true)
975 {
976 @GetWrapperStart(settings.IncludeWrapper, settings.Type, settings.WrapperElement, settings.IsRequired, settings.WrapperCssClass)
977 if ((settings.Label.IsNotNullOrEmpty() || settings.TranslateKeyForLabel.IsNotNullOrEmpty()) && renderLabel)
978 {
979 var attributes = new Dictionary<string, string>
980 {
981 {"class", GetAttributeString("form-label", settings.LabelCssClass)}
982 };
983
984 if (settings.Type != FieldType.Checkboxlist && settings.Type != FieldType.Radio)
985 {
986 attributes.Add("for", settings.SystemName);
987 }
988
989 @GetHtmlElement("label", attributes)
990 @InternalRenderLabel(settings)
991 @GetHtmlElement("label", true)
992 }
993 if (settings.Prepend.IsNotNullOrEmpty())
994 {
995 var attributes = new Dictionary<string, string>
996 {
997 {"class", "fieldPrepend input-group-addon"}
998 };
999 @GetHtmlElement("div", attributes)
1000 @settings.Prepend
1001 @GetHtmlElement("div", true)
1002 }
1003 if (settings.IncludeFieldWrapper)
1004 {
1005 @:<div class="fieldContainer hidden @settings.FieldWrapperCssClass">
1006 }
1007 }
1008
1009 @helper InternalRenderFieldFooter(FieldSettings settings)
1010 {
1011 if (settings.Icon.IsNotNullOrEmpty())
1012 {
1013 @RenderIcon(settings.Icon, settings.Tooltip, IconPosition.Left, true)
1014 }
1015 if (settings.Append.IsNotNullOrEmpty())
1016 {
1017 <div class="fieldAppend input-group-addon">@settings.Append</div>
1018 }
1019 if (settings.Description.IsNotNullOrEmpty())
1020 {
1021 <p class="help-block">@settings.Description</p>
1022 }
1023 if (settings.IncludeFieldWrapper)
1024 {
1025 @:</div>
1026 }
1027 @GetWrapperEnd(settings.IncludeWrapper, settings.WrapperElement)
1028 }
1029
1030 @helper InternalRenderQuantityField(int productStock, int productAvailableAmount, int selectedQuantity = 1, int productType = 0)
1031 {
1032 @InternalRenderQuantityField(productStock, productAvailableAmount, selectedQuantity, string.Empty, 10, false, false, productType)
1033 }
1034
1035 @helper InternalRenderQuantityField(int productStock, int productAvailableAmount, int selectedQuantity = 1, bool variantGroupsExistList = false)
1036 {
1037 @InternalRenderQuantityField(productStock, productAvailableAmount, selectedQuantity, string.Empty, 10, false, variantGroupsExistList)
1038 }
1039
1040 @helper InternalRenderQuantityField(int productStock, int productAvailableAmount, int selectedQuantity = 1, string fieldSystemName = "", int limit = 10, bool isCheckout = true, bool variantGroupsExistList = false, int productType = 0, string productId = "")
1041 {
1042 var isQuantityTextHidden = selectedQuantity < 10 && productStock > 0 || !isCheckout ? " hidden" : string.Empty;
1043 var isSelectDisabled = productStock <= 0 && !isCheckout;
1044 var quantityTextFieldSettings = new FieldSettings
1045 {
1046 Value = selectedQuantity.ToString(),
1047 SystemName = fieldSystemName.IsNullOrEmpty() ? "quantity" : fieldSystemName,
1048 Id = (fieldSystemName.IsNullOrEmpty() ? "quantity_" : fieldSystemName) + productId,
1049 Attributes = new Dictionary<string, string>
1050 {
1051 {"oninput", "this.value = this.value.slice(0, 5);"},
1052 {"data-productStock", productStock.ToString()},
1053 {"data-productAvailable", productAvailableAmount.ToString()},
1054 {"data-outofstock", Translate("Out of stock")},
1055 {"data-stocktranslate", Translate("The current stock is")},
1056 {"data-currentValue", selectedQuantity.ToString()}
1057 }
1058 };
1059
1060 if (productType != 1 && productType != 3)
1061 {
1062 quantityTextFieldSettings.Type = FieldType.Number;
1063 quantityTextFieldSettings.Label = Translate("Qty");
1064 quantityTextFieldSettings.CssClass = "col-xs-4 col-sm-7 quantityInput" + isQuantityTextHidden;
1065 quantityTextFieldSettings.LabelCssClass = productStock > 0 ? "" : "hidden";
1066 quantityTextFieldSettings.Attributes.Add("min", "1");
1067 quantityTextFieldSettings.Attributes.Add("onblur", "checkMinValue(this);");
1068
1069 <fieldset class="quantity-container pull-left">
1070 @if (isCheckout)
1071 {
1072 <div class="@isQuantityTextHidden quantityPriceContainer">
1073 @RenderField(quantityTextFieldSettings)
1074 @RenderBootstrapButton(new BootstrapButtonSettings {IconCssClass = "fa-refresh", CssClass = "submitQuantity btnCart-blue", ButtonType = BootstrapButtonSettings.BootstrapButtonType.Button})
1075 </div>
1076 }
1077 else
1078 {
1079 @RenderField(quantityTextFieldSettings)
1080 }
1081
1082 @if (selectedQuantity < limit)
1083 {
1084 var quantityOptionLimit = productStock <= 0 ? 10 : productStock >= limit || variantGroupsExistList ? limit : productStock + 1;
1085 var quantityFieldSettings = new FieldSettings
1086 {
1087 Type = FieldType.Select,
1088 SystemName = "quantitySelect",
1089 Id = "quantitySelect" + productId
1090 };
1091 if (isSelectDisabled)
1092 {
1093 quantityFieldSettings.Attributes.Add("disabled", "disabled");
1094 }
1095
1096 for (var num = 1; num < quantityOptionLimit; num++)
1097 {
1098 var cssClass = num >= quantityOptionLimit ? "hidden" : "";
1099 quantityFieldSettings.FieldOptionsList.Add(new FieldOption {Label = num.ToString(), Value = num.ToString(), IsSelected = selectedQuantity == num, CssClass = cssClass});
1100 }
1101
1102 if (productStock >= limit || variantGroupsExistList)
1103 {
1104 var limitPlus = limit + "+";
1105 var cssClass = variantGroupsExistList && productStock < limit ? "hidden" : "";
1106 quantityFieldSettings.FieldOptionsList.Add(new FieldOption {Label = limitPlus, Value = limitPlus, CssClass = cssClass});
1107 }
1108 @RenderField(quantityFieldSettings)
1109 }
1110 </fieldset>
1111 }
1112 else
1113 {
1114 quantityTextFieldSettings.Type = FieldType.Hidden;
1115 @RenderField(quantityTextFieldSettings)
1116 }
1117 }
1118
1119 @* Countries and Regions helpers *@
1120 @helper InternalRenderCountryAndRegionsJsVariables(Dynamicweb.Ecommerce.International.CountryCollection countries = null)
1121 {
1122 if (countries == null)
1123 {
1124 countries = Dynamicweb.Ecommerce.Services.Countries.GetCountries();
1125 }
1126
1127 if (countries.Any())
1128 {
1129 @: @SnippetStart("jsVariables") var countryRegions = {}; @SnippetEnd("jsVariables")
1130
1131 foreach (var country in countries.OrderBy(s => s.Name))
1132 {
1133 var regions = Dynamicweb.Ecommerce.Services.Countries.GetRegions(country.Code2);
1134
1135 if (regions.Any())
1136 {
1137 @: @SnippetStart("jsVariables") countryRegions.@( country.Code2) = {}; @SnippetEnd("jsVariables")
1138 <text>
1139 @SnippetStart("jsVariables")
1140 countryRegions.@( country.Code2).code = [];
1141 countryRegions.@( country.Code2).name = [];
1142 @SnippetEnd("jsVariables")
1143 </text>
1144 foreach (var region in regions.OrderBy(s => s.Name))
1145 {
1146 <text>
1147 @SnippetStart("jsVariables")
1148 countryRegions["@country.Code2"].code.push("@region.RegionCode");
1149 countryRegions["@country.Code2"].name.push("@region.Name");
1150 @SnippetEnd("jsVariables")
1151 </text>
1152 }
1153 }
1154 }
1155 }
1156 }
1157
1158 }@inherits RazorTemplateBase<RazorTemplateModel<Template>>
1159 @using Dynamicweb.Rendering
1160 @functions
1161 {
1162 public static bool IsBillingAddressReadOnly()
1163 {
1164 return Dna.Modules.Features.FeatureManager.IsEnabled("IsBillingAddressReadOnly", "Set to 'true' if the Billing Address should be read-only.");
1165 }
1166
1167 public static bool IsBillingAddressEditable()
1168 {
1169 return Dna.Modules.Features.FeatureManager.IsEnabled("IsBillingAddressEditable", "Set to 'true' if the Billing Address should be editable.");
1170 }
1171
1172 public static bool IsShippingAddressEditable()
1173 {
1174 return Dna.Modules.Features.FeatureManager.IsEnabled("IsShippingAddressEditable", "Set to 'true' if the Shipping Address should be editable.");
1175 }
1176
1177 public static bool ShowNoErpConnectionMessage()
1178 {
1179 return Dna.Modules.Features.FeatureManager.IsEnabled("showNoErpConnectionMessage", "Set to 'true' if want to show the 'No ERP Connection Message'.");
1180 }
1181
1182 public static bool ShowStateFieldAsDropdown()
1183 {
1184 return Dna.Modules.Features.FeatureManager.IsEnabled("showStateFieldAsDropdown", "Set to 'true' if the State field should be a drop-down.");
1185 }
1186 public static bool ShowVariantsAsDropdown()
1187 {
1188 return Dna.Modules.Features.FeatureManager.IsEnabled("showVariantsAsDropdown", "Set to 'true' if the Variant field should be a drop-down.");
1189 }
1190 public static bool ShowB2BLogin()
1191 {
1192 return Dna.Modules.Features.FeatureManager.IsEnabled("showB2BLogin", "Set to 'true' if it should display a login page.");
1193 }
1194 public static bool ShowRatings()
1195 {
1196 return Dna.Modules.Features.FeatureManager.IsEnabled("showRatrings", "Set to 'true' if ratings should be displayed.");
1197 }
1198 public static bool ShowReviews()
1199 {
1200 return Dna.Modules.Features.FeatureManager.IsEnabled("showReviews", "Set to 'true' if reviews should be displayed.");
1201 }
1202
1203 public static bool ShowRatingInProductList()
1204 {
1205 return Dna.Modules.Features.FeatureManager.IsEnabled("showRatingInProductList", "Set to 'true' if ratings in product list should be displayed.");
1206 }
1207 }
1208 @functions{
1209
1210 #region Css functions
1211
1212 public static string GetPalletColorNumber(int number = 0)
1213 {
1214 switch (number)
1215 {
1216 case 1:
1217 return "#666666";
1218 case 2:
1219 return "#092138";
1220 default:
1221 return "#ffffff";
1222 }
1223 }
1224
1225 public static string GetFontFamilyNumber(int number = 0)
1226 {
1227 switch (number)
1228 {
1229 case 1:
1230 return "font-family: Arial, sans-serif;";
1231 default:
1232 return "font-family: Helvetica, Arial, sans-serif;";
1233 }
1234 }
1235
1236 public static string GetFontSize(int fontSize = 0)
1237 {
1238 return fontSize >= 0 ? string.Concat("font-size: ", fontSize, "px;") : "font-size: 14px";
1239 }
1240
1241 #endregion Css functions
1242
1243 #region Icon functions
1244
1245 public static string GetIcon(string cssPartialClass, string label = "", string position = "")
1246 {
1247 var icon = "<i class='fa " + cssPartialClass + "'></i>";
1248 var spacing = string.Empty;
1249
1250 if (!label.IsNullOrEmpty())
1251 {
1252 spacing = " ";
1253 }
1254
1255 if (cssPartialClass.IsNullOrEmpty()) return label;
1256 if (position == IconPosition.Left.ToString() || position.IsNullOrEmpty())
1257 {
1258 return icon + spacing + label;
1259 }
1260 return label + spacing + icon;
1261 }
1262
1263 #endregion Icon functions
1264
1265 #region Address functions
1266
1267 public string GetAddressFormatted(User user, bool getRegionName = false, bool getCountryName = false, bool addLineBreakBetweenAddressAndCity = false, string splitBetweenRegionAndCountry = " ")
1268 {
1269 return GetAddressFormatted(user.Address, user.Address2, user.City, user.State, user.Zip, user.Country, getRegionName, getCountryName, addLineBreakBetweenAddressAndCity, splitBetweenRegionAndCountry);
1270 }
1271
1272 public string GetAddressFormatted(UserAddress userAddress, bool getRegionName = false, bool getCountryName = false, bool addLineBreakBetweenAddressAndCity = false, string splitBetweenRegionAndCountry = " ")
1273 {
1274 return GetAddressFormatted(userAddress.Address, userAddress.Address2, userAddress.City, userAddress.State, userAddress.Zip, userAddress.Country, getRegionName, getCountryName, addLineBreakBetweenAddressAndCity, splitBetweenRegionAndCountry);
1275 }
1276
1277 public string GetAddressFormatted(AddressSource addressSource, bool getRegionName = false, bool getCountryName = false, bool addLineBreakBetweenAddressAndCity = false, string splitBetweenRegionAndCountry = " ")
1278 {
1279 switch (addressSource)
1280 {
1281 case AddressSource.UserProfile:
1282 return GetAddressFormatted(
1283 GetString("UserManagement:User.Address"),
1284 GetString("UserManagement:User.Address2"),
1285 GetString("UserManagement:User.City"),
1286 GetString("UserManagement:User.State"),
1287 GetString("UserManagement:User.Zip"),
1288 GetString("UserManagement:User.Country"),
1289 getRegionName,
1290 getCountryName,
1291 addLineBreakBetweenAddressAndCity,
1292 splitBetweenRegionAndCountry
1293 );
1294 case AddressSource.EcomCustomer:
1295 return GetAddressFormatted(
1296 GetString("Ecom:Order.Customer.Address"),
1297 GetString("Ecom:Order.Customer.Address2"),
1298 GetString("Ecom:Order.Customer.City"),
1299 GetString("Ecom:Order.Customer.Region"),
1300 GetString("Ecom:Order.Customer.Zip"),
1301 GetString("Ecom:Order.Customer.Country"),
1302 getRegionName,
1303 getCountryName,
1304 addLineBreakBetweenAddressAndCity,
1305 splitBetweenRegionAndCountry
1306 );
1307 case AddressSource.EcomDelivery:
1308 return GetAddressFormatted(
1309 GetString("Ecom:Order.Delivery.Address"),
1310 GetString("Ecom:Order.Delivery.Address2"),
1311 GetString("Ecom:Order.Delivery.City"),
1312 GetString("Ecom:Order.Delivery.Region"),
1313 GetString("Ecom:Order.Delivery.Zip"),
1314 GetString("Ecom:Order.Delivery.Country"),
1315 getRegionName,
1316 getCountryName,
1317 addLineBreakBetweenAddressAndCity,
1318 splitBetweenRegionAndCountry
1319 );
1320 case AddressSource.UserAddress:
1321 throw new NotImplementedException("Not applicable");
1322 default:
1323 throw new ArgumentOutOfRangeException("addressSource property", addressSource, null);
1324 }
1325 }
1326
1327 public string GetAddressFormatted(string address, string address2, string city, string zip, string region, string country, bool getRegionName = false, bool getCountryName = false, bool addLineBreakBetweenAddressAndCity = false, string splitBetweenRegionAndCountry = " ")
1328 {
1329 var formattedAddress = new StringBuilder(address);
1330
1331 if (address2.IsNotNullOrEmpty())
1332 {
1333 formattedAddress.Append(string.Concat(" ",address2));
1334 }
1335 if (addLineBreakBetweenAddressAndCity && (city + region + country).IsNotNullOrEmpty())
1336 {
1337 formattedAddress.Append("<br/>");
1338 }
1339 if (city.IsNotNullOrEmpty())
1340 {
1341 formattedAddress.Append(string.Concat(" ",city));
1342 }
1343 if (zip.IsNotNullOrEmpty())
1344 {
1345 formattedAddress.Append(string.Concat(" ",zip));
1346 }
1347 if (region.IsNotNullOrEmpty())
1348 {
1349 formattedAddress.Append(zip.IsNotNullOrEmpty() ? string.Empty : ",");
1350 if (getRegionName && country.IsNotNullOrEmpty())
1351 {
1352 var getRegions = Dynamicweb.Ecommerce.Services.Countries.GetRegions(country);
1353 if(getRegions != null) {
1354 var regionName = getRegions.First(c => c.RegionCode == region).Name;
1355 region = regionName.IsNotNullOrEmpty() ? regionName : region;
1356 }
1357 }
1358 formattedAddress.Append(string.Concat(" ",region));
1359 }
1360
1361 if (country.IsNullOrEmpty())
1362 {
1363 return formattedAddress.ToString();
1364 }
1365
1366 formattedAddress.Append(splitBetweenRegionAndCountry.IsNotNullOrEmpty() ? splitBetweenRegionAndCountry : " ");
1367 if (getCountryName)
1368 {
1369 var getCountry = Dynamicweb.Ecommerce.Services.Countries.GetCountry(country);
1370 if(getCountry != null)
1371 {
1372 var countryName = getCountry.Name;
1373 country = countryName.IsNotNullOrEmpty() ? countryName : country;
1374 }
1375 }
1376 formattedAddress.Append(country);
1377
1378 return formattedAddress.ToString();
1379 }
1380
1381 #endregion Address functions
1382
1383 #region Field helper functions
1384
1385 const string HighlightedCountriesSplit = "----------------";
1386
1387 internal readonly List<string> HighlightedCountries = new List<string>
1388 {
1389 "CA",
1390 "US",
1391 HighlightedCountriesSplit
1392 };
1393
1394 #endregion Field helper functions
1395
1396 #region Generic functions
1397
1398 private static int FormatInteger(object value)
1399 {
1400 int num;
1401 if (value == null)
1402 {
1403 value = string.Empty;
1404 }
1405 return int.TryParse(value.ToString(), out num) ? num : 0;
1406 }
1407
1408 #endregion Generic functions
1409 }
1410 @{
1411 @* Tables and list helpers *@
1412 @helper RenderTableHeading(string label, string sortByField = "", string listType = "Order")
1413 {
1414 if (sortByField.IsNotNullOrEmpty())
1415 {
1416 var href = string.Empty;
1417 var icon = "fa-sort-amount-asc";
1418 var sortOrder = "asc";
1419
1420 if (listType == "Order" || listType == "Rma")
1421 {
1422 href = GetCustomerCenterSortUrl(sortByField, listType);
1423 if (GetSortFieldParameter("name") == sortByField)
1424 {
1425 sortOrder = GetSortFieldParameter("value", sortByField).ToLower();
1426 icon = "fa-sort-amount-" + sortOrder;
1427
1428 }
1429 }
1430 else if (listType == "DataList")
1431 {
1432 var sortByParameter = Sanitize.Parameter("sortby").IsNotNullOrEmpty() ? Sanitize.Parameter("sortby") : string.Empty;
1433 var sortOrderParameter = Sanitize.Parameter("sortorder").IsNotNullOrEmpty() ? Sanitize.Parameter("sortorder") : "ASC";
1434
1435 href = GetDataListSortUrl(sortByField);
1436 if (sortByParameter == sortByField)
1437 {
1438 sortOrder = sortOrderParameter.ToLower();
1439 icon = "fa-sort-amount-" + sortOrder;
1440 sortOrder = sortOrder == "asc" ? "desc" : "asc";
1441 }
1442 }
1443 <a href="@href" data-sortby="@sortByField" data-sortorder="@sortOrder.ToUpperInvariant()">
1444 @RenderIcon(icon, label, IconPosition.Right)
1445 </a>
1446 }
1447 else
1448 {
1449 @label
1450 }
1451 }
1452
1453 @helper RenderDataListItem(string label, string value, string labelCss = "col-xs-4 text-right", string valueCss = "col-xs-8", string alternativeValue = "", bool isLabelBold = true)
1454 {
1455 if (value.IsNotNullOrEmpty() || alternativeValue.IsNotNullOrEmpty())
1456 {
1457 var displayValue = alternativeValue.IsNullOrEmpty() ? value : alternativeValue;
1458
1459 <dt class="@labelCss">
1460 @if (isLabelBold)
1461 {
1462 @: <strong>
1463 }
1464 @label
1465 @if (isLabelBold)
1466 {
1467 @: </strong>
1468 }
1469 </dt>
1470 <dd class="@valueCss">
1471 @displayValue
1472 </dd>
1473 }
1474 }
1475
1476 @helper RenderTableRowSpacer(int height = 30, int colspan = 1)
1477 {
1478 if (height == 0)
1479 {
1480 height = 30;
1481 }
1482
1483 <tr>
1484 @if (colspan > 1)
1485 {
1486 @: <td colspan="@colspan" height="@height"></td>
1487 }
1488 else
1489 {
1490 <td height="@height"></td>
1491 }
1492 </tr>
1493 }
1494
1495 @helper RenderTableCellSpacer(int width = 10, int height = 10)
1496 {
1497 if (width == 0)
1498 {
1499 width = 10;
1500 }
1501 if (height == 0)
1502 {
1503 height = 10;
1504 }
1505 <td width="@width" height="@height"> </td>
1506 }
1507
1508
1509 @* Tab helpers *@
1510 @helper RenderTabContent(string tabKey, string tabLabel, string tabContent, string cssClass = "")
1511 {
1512 if (tabContent.IsNotNullOrEmpty())
1513 {
1514 @InternalRenderTabHeader("#" + tabKey, tabLabel, cssClass)
1515 <div class="col-xs-12 @cssClass" id="@tabKey">
1516 @tabContent
1517 </div>
1518 }
1519 }
1520
1521 @helper RenderTwoLineTabContent(string tabKey, string tabLabel, string tabContent1, string tabContent2, string cssClass = "")
1522 {
1523 if (tabContent1.IsNotNullOrEmpty() && tabContent2.IsNotNullOrEmpty())
1524 {
1525 @InternalRenderTabHeader("#" + tabKey, tabLabel, cssClass)
1526 <div class="col-xs-12 @cssClass" id="@tabKey">
1527 @tabContent1
1528 <div class="tabContentSeparation"></div>
1529 @tabContent2
1530 </div>
1531 }
1532 }
1533
1534
1535 @* Field helpers *@
1536 @helper RenderField(FieldSettings settings)
1537 {
1538 switch (settings.Type)
1539 {
1540 case FieldType.Button:
1541 case FieldType.Reset:
1542 case FieldType.Submit:
1543 @InternalRenderButtonField(settings)
1544 break;
1545 case FieldType.Checkbox:
1546 @InternalRenderCheckboxField(settings)
1547 break;
1548 case FieldType.Image:
1549 @InternalRenderImageField(settings)
1550 break;
1551 case FieldType.Checkboxlist:
1552 case FieldType.Radio:
1553 @InternalRenderRadioOrCheckboxListField(settings)
1554 break;
1555 case FieldType.Select:
1556 @InternalRenderSelectField(settings)
1557 break;
1558 case FieldType.Color:
1559 case FieldType.Date:
1560 case FieldType.DatetimeLocal:
1561 case FieldType.Email:
1562 case FieldType.File:
1563 case FieldType.Hidden:
1564 case FieldType.Password:
1565 case FieldType.Month:
1566 case FieldType.Number:
1567 case FieldType.Range:
1568 case FieldType.Search:
1569 case FieldType.Tel:
1570 case FieldType.Text:
1571 case FieldType.Time:
1572 case FieldType.Url:
1573 case FieldType.Week:
1574 @InternalRenderInputField(settings)
1575 break;
1576 case FieldType.Textarea:
1577 @InternalRenderTextareaField(settings)
1578 break;
1579 case FieldType.Textstring:
1580 @InternalRenderTextStringField(settings)
1581 break;
1582 case FieldType.Divider:
1583 @InternalRenderDividerField(settings)
1584 break;
1585 case FieldType.Datetime:
1586 @InternalRenderDateTimeField(settings)
1587 break;
1588 case FieldType.Unknown:
1589 @:<div style="color: #f00">Undefined FieldType: <strong>@settings.Type</strong></div>
1590 break;
1591 default:
1592 throw new NotSupportedException(string.Format("Unsupported Field Type: {0}.", settings.Type.ToString()));
1593 }
1594 }
1595
1596 @helper RenderCountriesDropdownField(List<string> countries, bool renderJsVariables = true, bool renderHighlightOptions = true, bool isFirstHardcodedOptionDisabled = true)
1597 {
1598 var settings = new FieldSettings
1599 {
1600 SystemName = "country",
1601 Id = "country",
1602 Label = Translate("Select your country:"),
1603 FirstHardcodedOptionLabel = Translate("All"),
1604 ValuesList = countries
1605 };
1606 @RenderCountriesDropdownField(settings, renderJsVariables, renderHighlightOptions, isFirstHardcodedOptionDisabled)
1607 }
1608
1609 @helper RenderCountriesDropdownField(FieldSettings settings, bool renderJsVariables = true, bool renderHighlightOptions = true, bool isFirstHardcodedOptionDisabled = true)
1610 {
1611
1612 if (settings.SystemName.IsNotNullOrEmpty())
1613 {
1614 const int limit = 10;
1615 const int numOfCountriesForHighlight = 10;
1616 var countries = EcommerceHelpers.GetEcomCountries();
1617 var numOfCountries = settings.LoopOptions.Any() ? settings.LoopOptions.Count : settings.ValuesList.Any() ? settings.ValuesList.Count : countries.Count;
1618
1619 settings.Assert(FieldType.Select);
1620 if (settings.FirstHardcodedOptionLabel.IsNullOrEmpty())
1621 {
1622 settings.FirstHardcodedOptionLabel = Translate("Select an option");
1623 }
1624 if (!settings.Attributes.ContainsKey("multiple") && !settings.Attributes.ContainsKey("data-live-search") && numOfCountries > limit)
1625 {
1626 settings.Attributes.Add("data-live-search", "true");
1627 }
1628
1629 if (renderJsVariables)
1630 {
1631 @InternalRenderCountryAndRegionsJsVariables(countries)
1632 }
1633
1634 @InternalRenderFieldHeader(settings)
1635 @GetHtmlElement("select", GetAttributes(settings))
1636 @InternalRenderOption(FieldOption.CreateOption(settings.FirstHardcodedOptionLabel, settings.FirstHardcodedOptionValue, settings.IsFirstHardcodedOptionSelected, isFirstHardcodedOptionDisabled))
1637
1638
1639 if (numOfCountries > numOfCountriesForHighlight)
1640 {
1641 @RenderSnippet("highlightedContries")
1642 }
1643
1644 if (settings.LoopOptions.Any())
1645 {
1646
1647 foreach (var country in settings.LoopOptions)
1648 {
1649 var countryName = country.GetString("Ecom:Country.Name");
1650 var countryCode = country.GetString("Ecom:Country.Code2");
1651
1652 if (renderHighlightOptions && HighlightedCountries.Any(c => c.Equals(countryCode, StringComparison.CurrentCultureIgnoreCase)))
1653 {
1654 @PopulateHighlightedCountries(countryName, countryCode)
1655 }
1656 else
1657 {
1658 @InternalRenderOption(FieldOption.CreateOption(countryName, countryCode))
1659 }
1660
1661 }
1662 }
1663 else if (settings.ValuesList.Any())
1664 {
1665 foreach (var countryCode in settings.ValuesList.OrderBy(s => s))
1666 {
1667 var countryName = countries.Any(c => c.Code2 == countryCode) ? countries.First(c => c.Code2 == countryCode).Name : countryCode;
1668
1669 if (renderHighlightOptions && HighlightedCountries.Any(c => c.Equals(countryCode, StringComparison.CurrentCultureIgnoreCase)))
1670 {
1671 @PopulateHighlightedCountries(countryName, countryCode)
1672 }
1673 else
1674 {
1675 @InternalRenderOption(FieldOption.CreateOption(countryName, countryCode))
1676 }
1677
1678 }
1679 }
1680 else
1681 {
1682 foreach (var country in countries.OrderBy(s => s.Name))
1683 {
1684 var countryCode = country.Code2;
1685
1686 if (renderHighlightOptions && HighlightedCountries.Any(c => c.Equals(countryCode, StringComparison.CurrentCultureIgnoreCase)))
1687 {
1688 @PopulateHighlightedCountries(country.Name, countryCode)
1689 }
1690 else
1691 {
1692 @InternalRenderOption(FieldOption.CreateOption(country.Name, countryCode))
1693 }
1694
1695 }
1696 }
1697
1698 if (renderHighlightOptions && numOfCountries > numOfCountriesForHighlight && HighlightedCountries.Any(c => HighlightedCountriesSplit.Equals(c, StringComparison.CurrentCultureIgnoreCase)))
1699 {
1700 @PopulateHighlightedCountries(HighlightedCountriesSplit, string.Empty, false, true)
1701 }
1702
1703 @GetHtmlElement("select", true)
1704
1705 @InternalRenderFieldFooter(settings)
1706 }
1707 }
1708
1709 @helper PopulateHighlightedCountries(string label, string value, bool isSelected = false, bool isDisabled = false)
1710 {
1711 HighlightedCountries.Remove(value);
1712 if (value.IsNullOrEmpty())
1713 {
1714 HighlightedCountries.Remove(label);
1715 }
1716 @SnippetStart("highlightedContries")
1717 @InternalRenderOption(FieldOption.CreateOption(label, value, isSelected, isDisabled))
1718 @SnippetEnd("highlightedContries")
1719 }
1720
1721
1722 @* Paging helpers *@
1723 @helper RenderPaging()
1724 {
1725 @RenderPaging(
1726 GetInteger("Ecom:CustomerCenter.Paging.NumPages"),
1727 "CCPage",
1728 GetString("Ecom:CustomerCenter.Paging.Back.URL"),
1729 GetString("Ecom:CustomerCenter.Paging.Forward.URL"),
1730 GetInteger("Ecom:CustomerCenter.Paging.CurrentPage"),
1731 GetLoop("Ecom:CustomerCenter.Paging.Pages"),
1732 "Ecom:CustomerCenter.Paging.PageIndex"
1733 )
1734 }
1735
1736 @helper RenderPaging(int numOfPages, string pageQueryParameter, int currentPage)
1737 {
1738 var queryParameters = HttpUtility.ParseQueryString(Dynamicweb.Context.Current.Request.Url.Query);
1739 var url = Helpers.GetCurrentUrl(true, true);
1740 var previousPageUrl = string.Empty;
1741 var nextPageUrl = string.Empty;
1742
1743 if (currentPage > 1)
1744 {
1745 queryParameters = Helpers.UpdateQueryStringKeyValue(queryParameters, pageQueryParameter, (currentPage - 1).ToString());
1746 previousPageUrl = Helpers.BuildUri(url, queryParameters).ToString();
1747 }
1748 if (currentPage < numOfPages)
1749 {
1750 queryParameters = Helpers.UpdateQueryStringKeyValue(queryParameters, pageQueryParameter, (currentPage + 1).ToString());
1751 nextPageUrl = Helpers.BuildUri(url, queryParameters).ToString();
1752 }
1753
1754 @RenderPaging(numOfPages, pageQueryParameter, previousPageUrl, nextPageUrl, currentPage)
1755 }
1756
1757 @helper RenderPaging(int numOfPages, string pageQueryParameter, string previousPageUrl, string nextPageUrl, int currentPage, List<LoopItem> pagesLoop = null, string pageNumTag = "", string pageHrefTag = "", bool includeWrapper = true)
1758 {
1759 if (numOfPages > 1)
1760 {
1761 @* NOTE: pageIndex needs to be a tag name, because it will be instanciated within the loop *@
1762 @* NOTE:
1763 queryParamenter == "PageNum" --> Product Catalog module
1764 queryParamenter == "page" --> Item Publisher module
1765 queryParamenter == "CC*" --> Customer Center module
1766 queryParamenter == "DWPagingPageNum" --> Data List module
1767 *@
1768
1769 var loopPageSize = 3;
1770 var startPage = 1;
1771 var endPage = numOfPages;
1772
1773 var pageQueryParameter2 = pageQueryParameter == "PageNum" || pageQueryParameter == "page" || pageQueryParameter == "DWPagingPageNum" ? string.Empty : Pageview.CurrentParagraph.ID.ToString();
1774 var pageNumQueryParameter = pageQueryParameter + pageQueryParameter2;
1775
1776 var queryParameters = HttpUtility.ParseQueryString(Dynamicweb.Context.Current.Request.Url.Query);
1777 queryParameters.Remove(pageNumQueryParameter);
1778 queryParameters.Remove("pid");
1779
1780 if (pageQueryParameter == "page")
1781 {
1782 queryParameters.Add("pid", Pageview.CurrentParagraph.ID.ToString());
1783 }
1784
1785 if (pagesLoop != null)
1786 {
1787 loopPageSize = pagesLoop.Count;
1788 endPage = 1;
1789 }
1790 else
1791 {
1792 var pageOffset = Math.Floor(Convert.ToDecimal(loopPageSize / 2));
1793 var middlePage = pageOffset + 1;
1794
1795 if (numOfPages > loopPageSize)
1796 {
1797 startPage = Convert.ToInt32(currentPage - pageOffset) < 1 ? 1 : Convert.ToInt32(currentPage - pageOffset);
1798 endPage = Convert.ToInt32(currentPage + pageOffset) > numOfPages ? numOfPages : Convert.ToInt32(currentPage + pageOffset);
1799
1800 if (currentPage < middlePage)
1801 {
1802 endPage = loopPageSize;
1803 }
1804 else if (currentPage >= middlePage)
1805 {
1806 if (numOfPages < currentPage + pageOffset)
1807 {
1808 startPage = numOfPages - loopPageSize;
1809 if (loopPageSize % 2 != 0)
1810 {
1811 startPage += 1;
1812 }
1813 }
1814
1815 if (loopPageSize % 2 == 0)
1816 {
1817 startPage += 1;
1818 }
1819 }
1820 }
1821 }
1822
1823 if (includeWrapper)
1824 {
1825 @:<div class="col-xs-12 text-center paginationContainer">
1826 }
1827 <ul class="pagination">
1828 @if (previousPageUrl.IsNotNullOrEmpty() && previousPageUrl != "#")
1829 {
1830 @InternalRenderPageItem(previousPageUrl, Translate("Previous"), "fa-caret-left", IconPosition.Left)
1831 }
1832 @if (pagesLoop != null)
1833 {
1834 @InternalRenderGoToFirstPage(queryParameters, pageNumQueryParameter, currentPage, numOfPages, loopPageSize, pagesLoop[0].GetInteger(pageNumTag))
1835 foreach (var page in pagesLoop)
1836 {
1837 var pageItemHref = pageQueryParameter == "PageNum" || pageQueryParameter == "page" ? page.GetString(pageHrefTag) : string.Empty;
1838 endPage = page.GetInteger(pageNumTag);
1839
1840 queryParameters.Remove(pageNumQueryParameter);
1841 if (pageItemHref.IsNotNullOrEmpty())
1842 {
1843 queryParameters.Add(pageNumQueryParameter, page.GetString(pageNumTag));
1844 }
1845 @InternalRenderPageItem(queryParameters, page.GetString(pageNumTag), page.GetInteger(pageNumTag) == currentPage ? "active" : string.Empty)
1846
1847 }
1848 @InternalRenderGoToLastPage(queryParameters, pageNumQueryParameter, currentPage, numOfPages, loopPageSize, endPage)
1849 }
1850 else
1851 {
1852 @InternalRenderGoToFirstPage(queryParameters, pageNumQueryParameter, currentPage, numOfPages, loopPageSize)
1853 for (var page = startPage; page <= endPage; page++)
1854 {
1855 queryParameters = Helpers.UpdateQueryStringKeyValue(queryParameters, pageNumQueryParameter, page.ToString());
1856 @InternalRenderPageItem(queryParameters, page.ToString(), page == currentPage ? "active" : string.Empty)
1857 }
1858 @InternalRenderGoToLastPage(queryParameters, pageNumQueryParameter, currentPage, numOfPages, loopPageSize, endPage)
1859 }
1860
1861 @if (nextPageUrl.IsNotNullOrEmpty() && nextPageUrl != "#")
1862 {
1863 @InternalRenderPageItem(nextPageUrl, Translate("Next"), "fa-caret-right", IconPosition.Right)
1864 }
1865 </ul>
1866 if (includeWrapper)
1867 {
1868 @:</div>
1869 }
1870 }
1871 }
1872
1873
1874 @* Generic helpers *@
1875 @helper RenderIcon(string cssPartialClass, string label = "", IconPosition position = IconPosition.Left, bool isLabelATooltip = false)
1876 {
1877 var icon = !isLabelATooltip ? "<i class='fa " + cssPartialClass + "'></i>" : "<i class='fa " + cssPartialClass + "' data-toggle='" + label + "'></i>";
1878 var spacing = string.Empty;
1879
1880 if (label.IsNotNullOrEmpty())
1881 {
1882 spacing = " ";
1883 }
1884 if (cssPartialClass.IsNotNullOrEmpty())
1885 {
1886 if (isLabelATooltip)
1887 {
1888 @icon
1889 }
1890 else if (position == IconPosition.Left)
1891 {
1892 @icon
1893 @spacing
1894 @label
1895 }
1896 else
1897 {
1898 @label
1899 @spacing
1900 @icon
1901 }
1902 }
1903 else
1904 {
1905 @label
1906 }
1907 }
1908
1909 @helper RenderStackedIcons(string cssPrincipalPartialClass, string cssSecondaryPartialClass, string label = "", IconPosition position = IconPosition.Left, bool isLabelATooltip = false)
1910 {
1911 var spacing = string.Empty;
1912 var icon = new StringBuilder("<span class='fa-stack'>");
1913
1914 icon.Append(!isLabelATooltip ? "<i class='fa " + cssPrincipalPartialClass + " fa-stack-2x'></i>" : "<i class='fa " + cssPrincipalPartialClass + " fa-stack-2x' data-toggle='" + label + "'></i>");
1915 icon.Append("<i class='fa " + cssSecondaryPartialClass + " fa-stack-1x'></i>");
1916 icon.Append("</span>");
1917
1918 if (label.IsNotNullOrEmpty())
1919 {
1920 spacing = "<text> </text>";
1921 }
1922 if (cssPrincipalPartialClass.IsNotNullOrEmpty() && cssSecondaryPartialClass.IsNotNullOrEmpty())
1923 {
1924 if (isLabelATooltip)
1925 {
1926 @icon.ToString()
1927 }
1928 else if (position == IconPosition.Left)
1929 {
1930 @icon.ToString()
1931 @spacing
1932 @label
1933 }
1934 else
1935 {
1936 @label
1937 @spacing
1938 @icon.ToString()
1939 }
1940 }
1941 else
1942 {
1943 @label
1944 }
1945 }
1946
1947 @helper RenderAction(IconAction action, string href = "", string title = "", string onClickConfirm = "")
1948 {
1949 var attributes = new Dictionary<string, string>();
1950
1951 if (title.IsNotNullOrEmpty())
1952 {
1953 attributes.Add("title", title);
1954 }
1955 if (onClickConfirm.IsNotNullOrEmpty())
1956 {
1957 attributes.Add("onclick", "return confirm('" + onClickConfirm + "');");
1958 }
1959 if (href.IsNotNullOrEmpty())
1960 {
1961 attributes.Add("href", href);
1962 }
1963 @RenderAction(action, href, attributes)
1964 }
1965
1966 @helper RenderAction(IconAction action, string href, Dictionary<string, string> attributes)
1967 {
1968 var icon = string.Empty;
1969 var linkAttributes = string.Empty;
1970 var label = Translate(action.ToString());
1971
1972 switch (action)
1973 {
1974 case IconAction.Add:
1975 break;
1976 case IconAction.View:
1977 icon = "fa-eye";
1978 break;
1979 case IconAction.Edit:
1980 icon = "fa-edit";
1981 break;
1982 case IconAction.Cancel:
1983 case IconAction.Remove:
1984 icon = "fa-times";
1985 break;
1986 case IconAction.Delete:
1987 icon = "fa-trash";
1988 break;
1989 case IconAction.Print:
1990 icon = "fa-print";
1991 attributes.Add("target", "_blank");
1992 label = string.Empty;
1993 break;
1994 case IconAction.Save:
1995 break;
1996 case IconAction.Reset:
1997 break;
1998 case IconAction.Undo:
1999 break;
2000 case IconAction.Reorder:
2001 icon = "fa-repeat";
2002 break;
2003 case IconAction.SetDefault:
2004 icon = "fa-times";
2005 label = string.Empty;
2006 break;
2007 case IconAction.IsDefault:
2008 icon = "fa-check";
2009 label = string.Empty;
2010 break;
2011 default:
2012 throw new NotSupportedException("An action is needed to render this helper!");
2013 }
2014 if (icon.IsNotNullOrEmpty())
2015 {
2016 if (href.IsNotNullOrEmpty())
2017 {
2018 @GetHtmlElement("a", GetAttributes(attributes))
2019 @RenderIcon(icon, label)
2020 @GetHtmlElement("a", true)
2021 }
2022 else if (label.IsNullOrEmpty())
2023 {
2024 @RenderIcon(icon)
2025 }
2026 }
2027
2028 }
2029
2030 @helper RenderBootstrapButton(BootstrapButtonSettings settings)
2031 {
2032 var attributes = new StringBuilder(GetAttribute("class", "btn " + (settings.CssClass.IsNotNullOrEmpty() ? settings.CssClass : "btn-default")));
2033 attributes.Append(GetAttribute("target", settings.Target));
2034 attributes.Append(GetAttribute("href", settings.Href));
2035 attributes.Append(GetAttribute("name", settings.SystemName));
2036 attributes.Append(GetAttribute("id", settings.Id));
2037 attributes.Append(GetAttribute("value", settings.Value));
2038 if (settings.ButtonType == BootstrapButtonSettings.BootstrapButtonType.Button && !settings.Attributes.ContainsKey("type"))
2039 {
2040 settings.Attributes.Add("type","submit");
2041 }
2042
2043 attributes.Append(GetAttributes(settings.Attributes));
2044 string htmlElement;
2045
2046 switch (settings.ButtonType)
2047 {
2048 case BootstrapButtonSettings.BootstrapButtonType.Button:
2049 htmlElement = "button";
2050 break;
2051 case BootstrapButtonSettings.BootstrapButtonType.Anchor:
2052 htmlElement = "a";
2053 break;
2054 default:
2055 throw new NotSupportedException(string.Format("Unsupported Bootstrap Button type: {0}.", settings.ButtonType.ToString()));
2056 }
2057 @GetHtmlElement(htmlElement, attributes.ToString())
2058 @RenderIcon(settings.IconCssClass, settings.Label, settings.IconPosition)
2059 @GetHtmlElement(htmlElement, true)
2060 }
2061
2062 @helper RenderAddToCart(string productId, string productVariantId, int availableAmount = 0, bool doNotRenderHiddenFields = false)
2063 {
2064 var addToCartButtonSettings = new BootstrapButtonSettings
2065 {
2066 Label = Translate("Add to Cart"),
2067 CssClass = availableAmount <= 0 ? "btn-default addToCartSubmit disabled" : "btn-default addToCartSubmit",
2068 Href = string.Concat(Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(Dynamicweb.Content.Services.Pages.GetPageByNavigationTag(Pageview.AreaID, "MiniCart").ID),"?productid=", productId, "&variantID=", productVariantId, "&cartcmd=add"),
2069 IconCssClass = "fa-shopping-cart",
2070 Attributes = new Dictionary<string, string>
2071 {
2072 {"data-add", Translate("Add to Cart")},
2073 {"data-added", Translate("Added")},
2074 {"data-outofstock", Translate("Out of stock")},
2075 {"data-stock", availableAmount.ToString()}
2076 }
2077 };
2078 @RenderBootstrapButton(addToCartButtonSettings)
2079 if (!doNotRenderHiddenFields)
2080 {
2081 @RenderField(FieldSettings.CreateHiddenField("redirect", "false", "redirect" + productId))
2082 @RenderField(FieldSettings.CreateHiddenField("cartcmd", "add", "cartcmd" + productId))
2083 @RenderField(FieldSettings.CreateHiddenField("productid", productId, "productId" + productId))
2084 @RenderField(FieldSettings.CreateHiddenField("variantid", productVariantId, "variantId" + productId + productVariantId))
2085 }
2086 @RenderField(FieldSettings.CreateSubmitField(Translate("Add to Cart"), "hidden"))
2087 }
2088
2089 @helper RenderSocialMediaShare()
2090 {
2091 <div class="shareIcons">
2092 <span>@Translate("Share")</span>
2093 @RenderSocialMedia(false, true)
2094 </div>
2095 }
2096
2097 @helper RenderOpenGraphMeta(string type, string image, string title, string teaser = "", string imageAlt = "")
2098 {
2099 var culture = Pageview.Area.Culture.Replace("-", "_");
2100 teaser = System.Text.RegularExpressions.Regex.Replace(teaser, "<.*?>", string.Empty);
2101 if (type.IsNullOrEmpty())
2102 {
2103 type = "article";
2104 }
2105 if (imageAlt.IsNullOrEmpty())
2106 {
2107 imageAlt = title;
2108 }
2109
2110 @SnippetStart("OGMeta")
2111 <meta property="og:title" content="@HttpUtility.HtmlEncode(title)"/>
2112 <meta property="og:image" content="@string.Concat(Helpers.GetCurrentUrl(true), image)"/>
2113 <meta property="og:image:width" content="600"/>
2114 <meta property="og:image:height" content="600"/>
2115 <meta property="og:image:alt" content="@HttpUtility.HtmlEncode(imageAlt)"/>
2116 <meta property="og:site_name" content="@Pageview.Area.Item["CompanyName"]"/>
2117 <meta property="og:url" content="@Helpers.GetCurrentUrl()"/>
2118 <meta property="og:description" content="@HttpUtility.HtmlEncode(teaser)"/>
2119 <meta property="og:type" content="@type"/>
2120 <meta property="og:locale" content="@culture"/>
2121 @SnippetEnd("OGMeta")
2122 }
2123
2124 @helper RenderSocialMedia(bool isEmailTemplate = false, bool isToShare = false)
2125 {
2126 var page = Dynamicweb.Extensibility.ServiceLocator.Current.GetPageService().GetPage(Dynamicweb.Content.Services.Pages.GetPageByNavigationTag(Pageview.AreaID, "GeneralSettings").ID);
2127 var generalSettings = Dynamicweb.Content.Items.Item.GetItemById(page.ItemType, page.ItemId);
2128
2129 if(generalSettings["SocialMedia"] != null) {
2130 var socialMedia = Dynamicweb.Content.Items.ItemList.GetItemListById(int.Parse(generalSettings["SocialMedia"].ToString()));
2131
2132 if(socialMedia.Relations.Any())
2133 {
2134 if(!isEmailTemplate)
2135 {
2136 @:<ul class="socialMedia">
2137 }
2138 foreach (var r in socialMedia.Relations)
2139 {
2140 var socialNetwork = Dynamicweb.Content.Items.Item.GetItemById("SocialLinks", r.Id);
2141 var className = (socialNetwork["Icon"] ?? "").ToString();
2142 var socialName = (socialNetwork["Name"] ?? "").ToString();
2143 var socialLink = (socialNetwork["Link"] ?? "").ToString();
2144 var shareLink = (socialNetwork["ShareURL"] ?? "").ToString();
2145
2146 if (isEmailTemplate)
2147 {
2148 @:
2149 <a title="@socialName" target="_blank" href="@socialLink">@socialName</a>
2150 @:
2151 }
2152 else if(!isToShare || shareLink.IsNotNullOrEmpty())
2153 {
2154 <li>
2155 <a title="@socialName" class="@className fa" target="_blank" data-sharehref="@
[email protected]()" href="@socialLink"><span class="hidden">@socialName</span></a>
2156 </li>
2157 }
2158 }
2159 if(!isEmailTemplate)
2160 {
2161 @:</ul>
2162 }
2163 }
2164 }
2165 }
2166
2167 @helper RenderNoResults(string wording, string title = "", bool hasWrapper = false, string wrapperClass = "col-xs-12 noPadding" )
2168 {
2169 if (hasWrapper)
2170 {
2171 @:<div class="noResultsWrapper @wrapperClass">
2172 }
2173 if (title.IsNotNullOrEmpty())
2174 {
2175 <h2>@title</h2>
2176 }
2177 <p>@wording</p>
2178 if (hasWrapper)
2179 {
2180 @:</div>
2181 }
2182 }
2183
2184 @helper RenderImage(ImageSettings imageSettings)
2185 {
2186 var imageMarkup = new StringBuilder();
2187 var widthAndHeight = GetWidthAndHeightFromQueryString(imageSettings.Source);
2188 var widthAndHeightForMobile = GetWidthAndHeightFromQueryString(imageSettings.SourceForMobile, true);
2189 var widthAndHeightForTablet = GetWidthAndHeightFromQueryString(imageSettings.SourceForTablet, true);
2190
2191 if (!imageSettings.Attributes.ContainsKey("width") && widthAndHeight.ContainsKey("width") && widthAndHeight["width"].IsNotNullOrEmpty())
2192 {
2193 imageSettings.Attributes.Add("width", widthAndHeight["width"]);
2194 }
2195 if (!imageSettings.Attributes.ContainsKey("height") && widthAndHeight.ContainsKey("height") && widthAndHeight["height"].IsNotNullOrEmpty())
2196 {
2197 imageSettings.Attributes.Add("height", widthAndHeight["height"]);
2198 }
2199 if (!imageSettings.Attributes.ContainsKey("class"))
2200 {
2201 imageSettings.Attributes.Add("class", "img-responsive " + imageSettings.CssClass);
2202 }
2203 if (!imageSettings.Attributes.ContainsKey("src"))
2204 {
2205 imageSettings.Attributes.Add("src", imageSettings.Source);
2206 }
2207 if (!imageSettings.Attributes.ContainsKey("alt"))
2208 {
2209 imageSettings.Attributes.Add("alt", imageSettings.AltText);
2210 }
2211 if (!imageSettings.Attributes.ContainsKey("title"))
2212 {
2213 imageSettings.Attributes.Add("title", imageSettings.Title);
2214 }
2215
2216 if (imageSettings.IncludeWrapper)
2217 {
2218 var wrapperAttributes = new Dictionary<string, string>();
2219 if (imageSettings.WrapperCssClass.IsNotNullOrEmpty())
2220 {
2221 wrapperAttributes.Add("class", imageSettings.WrapperCssClass);
2222 }
2223
2224 imageMarkup.Append(GetHtmlElement(imageSettings.WrapperElement, wrapperAttributes));
2225 }
2226
2227 if (imageSettings.Href.IsNotNullOrEmpty())
2228 {
2229 var linkAttributes = new Dictionary<string, string> {{"href", imageSettings.Href}};
2230 if (imageSettings.HrefCssClass.IsNotNullOrEmpty())
2231 {
2232 linkAttributes.Add("class", imageSettings.HrefCssClass);
2233 }
2234 if (imageSettings.HrefTarget.IsNotNullOrEmpty())
2235 {
2236 linkAttributes.Add("target", imageSettings.HrefTarget);
2237 }
2238
2239 imageMarkup.Append(GetHtmlElement("a", linkAttributes));
2240 }
2241
2242 if (widthAndHeightForMobile.Any() || widthAndHeightForTablet.Any())
2243 {
2244 imageMarkup.Append(GetHtmlElement("picture"));
2245
2246 imageMarkup.Append(GetHtmlElement("source"));
2247
2248 if (widthAndHeightForMobile.Any())
2249 {
2250 imageMarkup.Append(GetHtmlElement("srcset", widthAndHeightForMobile));
2251 }
2252
2253 if (widthAndHeightForTablet.Any())
2254 {
2255 imageMarkup.Append(GetHtmlElement("srcset", widthAndHeightForTablet));
2256 }
2257
2258 imageMarkup.Append(GetHtmlElement("source", true));
2259 }
2260
2261 imageMarkup.Append(GetHtmlElement("img", imageSettings.Attributes, true));
2262
2263 if (imageSettings.SourceForMobile.IsNotNullOrEmpty() || imageSettings.SourceForTablet.IsNotNullOrEmpty())
2264 {
2265 imageMarkup.Append(GetHtmlElement("picture", true));
2266 }
2267
2268 if (imageSettings.Href.IsNotNullOrEmpty())
2269 {
2270 imageMarkup.Append(GetHtmlElement("a", true));
2271 }
2272
2273 if (imageSettings.IncludeWrapper)
2274 {
2275 imageMarkup.Append(GetHtmlElement(imageSettings.WrapperElement, true));
2276 }
2277
2278 @imageMarkup.ToString()
2279 }
2280
2281 @helper RenderHtmlElementBetweenEachString(List<string> listOfStrings, string htmlElement = "br" )
2282 {
2283 foreach (var str in listOfStrings)
2284 {
2285 if (str.IsNullOrEmpty()){continue;}
2286 @(string.Concat(str, GetHtmlElement(htmlElement, true)))
2287 }
2288 }
2289
2290 @helper RenderProductPrice(string productPrice = "")
2291 {
2292 var showNoErpConnectionMessage = ShowNoErpConnectionMessage();
2293 var isWebServiceConnectionAvailable = Dna.Ecommerce.LiveIntegration.TemplatesHelper.IsWebServiceConnectionAvailable();
2294
2295 if (!isWebServiceConnectionAvailable && showNoErpConnectionMessage)
2296 {
2297 if (productPrice.IsNullOrEmpty())
2298 {
2299 @RenderNoErpConnectionMessage()
2300 }
2301 else
2302 {
2303 <span class="noErpConnection">@Translate("Unavailable")</span>
2304 }
2305 }
2306 else
2307 {
2308 @productPrice
2309 }
2310 }
2311
2312 @helper RenderNoErpConnectionMessage()
2313 {
2314 <div class="col-xs-12 warningBox">
2315 <p>@Translate("Pricing and inventory are currently not available. Please check back soon")</p>
2316 </div>
2317 }
2318 }
2319 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
2320 @using Dynamicweb.Rendering
2321 @using System
2322 @using Dynamicweb.Security.UserManagement
2323 @using System.Collections.Generic
2324 @using Dna.Frontend.Forms
2325 @using Dynamicweb.Forms
2326 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
2327 @using Dynamicweb.Rendering
2328 @using System.Collections.Generic
2329 @using Dna.Frontend.Forms
2330 @using Dynamicweb.Forms
2331 @{
2332
2333 @helper InternalRenderGiftCardAmount(bool isGiftCard = false, string productPrice = "", string productId = "")
2334 {
2335 if (isGiftCard)
2336 {
2337 var giftCardAmountFieldSettings = new FieldSettings
2338 {
2339 Type = FieldType.Number,
2340 SystemName = "Amount",
2341 Id = "Amount" + productId,
2342 Placeholder = Translate("amount"),
2343 Value = productPrice,
2344 IncludeWrapper = true,
2345 WrapperCssClass = "pull-left giftCardAmount",
2346 Attributes = new Dictionary<string, string>
2347 {
2348 {"step", "0.01"},
2349 {"min", "0.01"}
2350 }
2351 };
2352 @RenderField(giftCardAmountFieldSettings)
2353 }
2354 }
2355
2356 }
2357 @{
2358 @helper RenderProductReviewsCount(int count = -1)
2359 {
2360 if (ShowReviews() && ShowRatings())
2361 {
2362 if (count == -1)
2363 {
2364 count = GetInteger("Comments.Count");
2365 }
2366 <span>@string.Concat(count, " ", count == 1 ? Translate("Review") : Translate("Reviews"))</span>
2367 }
2368
2369 }
2370 @helper RenderRating(double rating)
2371 {
2372 if (ShowRatings())
2373 {
2374 <ul class="rating">
2375 @for (var s = 5; s > 0; s--)
2376 {
2377 var cssClass = string.Empty;
2378 var iconCssClass = "fa-star";
2379
2380 if (Math.Abs(s - Math.Ceiling(rating)) <= 0)
2381 {
2382 cssClass = "class='star'";
2383 iconCssClass = !(Math.Abs(rating - Math.Round(rating)) <= 0) ? "fa-star-half-o" : "fa-star";
2384 }
2385 else if (Math.Ceiling(rating) < s)
2386 {
2387 iconCssClass = "fa-star-o";
2388 }
2389
2390 <li data-star="@s" @cssClass>
2391 @RenderIcon(iconCssClass)
2392 </li>
2393 }
2394 </ul>
2395 }
2396 }
2397
2398 @helper RenderStockStatus(string stockStatus, int productType = 0)
2399 {
2400 // Only show if it's not a Service or Gift Card
2401 if (productType != 1 && productType != 3)
2402 {
2403 <div class="col-xs-12 noPadding stockStatus">
2404 @RenderIcon(stockStatus, Translate("Stock"))
2405 </div>
2406 }
2407 }
2408
2409 @helper RenderFavorites(bool productIsFavorite, string productId, string variantId, string productLanguage, bool variantCombinations = false, bool iconOnly = false)
2410 {
2411 // Favorites
2412 var favoritesUrl = "/Default.aspx?Id=" + Pageview.Page.ID + "&CC{{favoriteAction}}MyLists=" + productId + "&CC{{favoriteAction}}ListVariantID=" + variantId + "&CC{{favoriteAction}}ListLanguageID=" + productLanguage;
2413 var addToFavorites = favoritesUrl.Replace("{{favoriteAction}}", "AddTo");
2414 var removeFromFavorites = favoritesUrl.Replace("{{favoriteAction}}", "RemoveFrom");
2415 var favoriteUrl = productIsFavorite ? removeFromFavorites : addToFavorites;
2416 var iconLabel = !iconOnly ? Translate(productIsFavorite ? "Remove From List" : "Add to List") : string.Empty;
2417 if (User.IsExtranetUserLoggedIn() &&
2418 Dynamicweb.Environment.ExecutingContext.IsFrontEnd() &&
2419 !variantCombinations)
2420 {
2421 <a class="btn-gold-outline favorite" data-add="@addToFavorites" data-remove="@removeFromFavorites" data-favorite="@productIsFavorite" data-user="@User.IsExtranetUserLoggedIn()" data-addText='@Translate("Add to List")' data-removeText='@Translate("Remove from List")' href="@favoriteUrl">
2422 @RenderIcon(productIsFavorite ? "fa-heart" : "fa-heart-o", iconLabel)
2423 </a>
2424 }
2425 }
2426
2427 @helper RenderQuantitySelector(bool variantGroupsExistList, int productStock, int productType = 0, string productId = "")
2428 {
2429 if (Pageview.Area.Item["ShowQuantityField"].ToString() == "True")
2430 {
2431 @InternalRenderQuantityField(productStock, productStock, 1, string.Empty, 10, false, variantGroupsExistList, productType, productId)
2432 }
2433 else
2434 {
2435 var quantityTextFieldSettings = new FieldSettings
2436 {
2437 Type = FieldType.Text,
2438 Value = "1",
2439 SystemName = "quantity",
2440 Id = "quantity" + productId,
2441 Attributes = new Dictionary<string, string>
2442 {
2443 {"oninput", "this.value = this.value.slice(0, 5);"},
2444 {"data-productStock", productStock.ToString()},
2445 {"data-outofstock", Translate("Out of stock")},
2446 {"data-stocktranslate", Translate("The current stock is")}
2447 }
2448 };
2449
2450 if (productType != 1 && productType != 3)
2451 {
2452 quantityTextFieldSettings.Type = FieldType.Number;
2453 quantityTextFieldSettings.Label = Translate("Qty");
2454 quantityTextFieldSettings.CssClass = "quantityInput hidden";
2455 }
2456 else
2457 {
2458 quantityTextFieldSettings.Type = FieldType.Hidden;
2459 }
2460 @RenderField(quantityTextFieldSettings)
2461 }
2462 }
2463
2464 @helper RenderProductCompare(int productType, string productId, string variantId = "", string productLanguage = "")
2465 {
2466 var isGiftCard = productType == 3;
2467
2468 if (!isGiftCard)
2469 {
2470 var compareLink = productId;
2471 compareLink += productLanguage.IsNotNullOrEmpty() ? "$" + productLanguage : "";
2472 compareLink += variantId.IsNotNullOrEmpty() ? "$" + variantId : "";
2473 const int compareLimit = 3;
2474
2475 @RenderField(new FieldSettings
2476 {
2477 Type = FieldType.Checkbox,
2478 Label = Translate("Add to compare"),
2479 SystemName = "addToCompare_" + productId,
2480 IncludeWrapper = true,
2481 WrapperElement = "div",
2482 WrapperCssClass = "addToCompare",
2483 Attributes = new Dictionary<string, string>
2484 {
2485 {"data-link", compareLink},
2486 {"data-maxcompare", string.Concat(Translate("Maximum to compare"), ": ", compareLimit)}
2487 }
2488 })
2489 }
2490 }
2491 }
2492 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
2493 @using System
2494 @using System.Collections.Generic
2495 @using Dynamicweb.Rendering
2496 @using Dna.Frontend
2497 @using System.Linq
2498 @using Dna.Frontend.UI
2499 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
2500 @using System
2501 @using Dynamicweb.Rendering
2502 @using System.Collections.Generic
2503 @using System.IO
2504 @using System.Linq
2505 @using System.Text.RegularExpressions
2506 @using Dna.Frontend
2507 @using Dna.Frontend.UI
2508 @using Dynamicweb.Core
2509 @functions
2510 {
2511 public string GetVariantImages(string defaultMedia, string fileNamingPart, string defaultName = "")
2512 {
2513 if (defaultMedia.IsNullOrEmpty()) return string.Empty;
2514 var images = string.Empty;
2515 var pattern = Pageview.Area.Item["Multiple_ProductImagesCharacter"] + "*";
2516 var fileName = string.Concat(defaultMedia.Replace(Images.GetProductImageFolder(), string.Empty, RegexOptions.IgnoreCase).Replace(".jpg", string.Empty), pattern);
2517 var mediaList = (List<Tuple<string,string,FileType>>) GetMediaFilesInFolder(defaultMedia, fileName, defaultName);
2518
2519 fileNamingPart = StringHelpers.SanitizeFileName(fileNamingPart) + Pageview.Area.Item["Multiple_ProductImagesCharacter"] + "*";
2520 mediaList.AddRange(GetMediaFilesInFolder(defaultMedia, fileNamingPart, defaultName, false));
2521
2522 return !mediaList.Any() ? images : mediaList.GroupBy(media => media.Item1).Select(group => group.First()).Where(imageStr => imageStr.Item1.IsNotNullOrEmpty()).Where(imageStr => imageStr.Item1.IsImageFile()).Aggregate(images, (current, mediaString) => current + (current.IsNullOrEmpty() ? mediaString.Item1 : string.Concat(",", mediaString.Item1)));
2523 }
2524 }
2525 @{
2526
2527 @helper InternalRenderProductThumbnailItem(Tuple<string,string,FileType> image)
2528 {
2529 if (image.Item1.IsNotNullOrEmpty())
2530 {
2531 <li data-type='@Path.GetFileNameWithoutExtension(image.Item1)'>
2532 @switch (image.Item3)
2533 {
2534 case FileType.Image:
2535 var imageSettings = new ImageSettings
2536 {
2537 @*START CUSTOM CODE*@
2538 Source = $"/Admin/Public/GetImage.ashx?image={image.Item1}&width=105&Format=WebP&Quality=100",
2539 @*END CUSTOM CODE*@
2540 AltText = image.Item2,
2541 Attributes = new Dictionary<string, string>
2542 {
2543 @*START CUSTOM CODE*@
2544 {"data-large", $"/Admin/Public/GetImage.ashx?image={image.Item1}&width=600&Format=WebP&Quality=100"},
2545 {"data-image", $"/Admin/Public/GetImage.ashx?image={image.Item1}&width=600&height=350&Format=WebP&Quality=100&fillcanvas=true"}
2546 @*END CUSTOM CODE*@
2547 }
2548 };
2549 @RenderImage(imageSettings)
2550 break;
2551 case FileType.Video:
2552 <video data-image="@image.Item1" width="100%" src="@image.Item1">Your browser does not support the video tag.</video>
2553 break;
2554 default:
2555 throw new ArgumentOutOfRangeException();
2556 }
2557 </li>
2558 }
2559 }
2560
2561 }
2562 @{
2563
2564 @helper RenderProductThumbnails(string defaultMedia, string productNumber, string productFileNamingPart, string productName = "")
2565 {
2566 var fileName = productNumber + productFileNamingPart;
2567 fileName = StringHelpers.SanitizeFileName(fileName) + Pageview.Area.Item["Multiple_ProductImagesCharacter"] + "*";
2568
2569 productFileNamingPart = StringHelpers.SanitizeFileName(productFileNamingPart) + Pageview.Area.Item["Multiple_ProductImagesCharacter"] + "*";
2570
2571 var mediaList = (List<Tuple<string,string,FileType>>) GetMediaFilesInFolder(defaultMedia, fileName, productName);
2572 mediaList.AddRange(GetMediaFilesInFolder(defaultMedia, productFileNamingPart, productName, false));
2573
2574 if(mediaList.Any())
2575 {
2576 <div id="imgThumbs" class="col-xs-12 noPaddingLeft">
2577 <ul>
2578 @foreach (var imageStr in mediaList)
2579 {
2580 @InternalRenderProductThumbnailItem(imageStr)
2581 }
2582 </ul>
2583 </div>
2584 }
2585 }
2586
2587 @helper RenderDownloadsTab()
2588 {
2589 var productDownloads = GetPageIdByNavigationTag("ProductDownloads");
2590 var productIdForDownloadsTab = GetString("Ecom:Product.ID");
2591 if (productDownloads != 0 && !string.IsNullOrWhiteSpace(productIdForDownloadsTab))
2592 {
2593 var downloadsFilter = $"Products contains 'p_{productIdForDownloadsTab},' or Products contains 'p_{productIdForDownloadsTab}:' or Products ends with 'p_{productIdForDownloadsTab}'";
2594
2595 @RenderItemList(new
2596 {
2597 ItemType = "ProductDownloads",
2598 ListSourceType = "Page",
2599 ListSourcePage = productDownloads,
2600 ItemFieldsList = "*",
2601 ListTemplate = "ItemPublisher/List/ProductDownloads.cshtml",
2602 ListPageSize = 99,
2603 IncludeParagraphItems = true,
2604 Filter = downloadsFilter
2605 })
2606 }
2607 }
2608
2609 }
2610 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
2611 @using System
2612 @using Dynamicweb.Rendering
2613 @using System.Collections.Generic
2614 @using System.Linq
2615 @using Dna.Frontend
2616 @{
2617 @helper RenderRapidoVariantsEngine(bool isVariantRequest)
2618 {
2619 var variantGroups = GetLoop("VariantGroups");
2620 if (variantGroups.Any())
2621 {
2622 string pageId = GetGlobalValue("Global:Page.ID").ToString();
2623 string productId = GetString("Ecom:Product.ID");
2624 string variantSelection = !String.IsNullOrEmpty(System.Web.HttpContext.Current.Request.QueryString.Get("variantId")) ? System.Web.HttpContext.Current.Request.QueryString.Get("variantId").Replace(".", ",") : "";
2625
2626 var webAvailableVariantIds = new List<string>();
2627 var variantCombinationsObject = new List<Array>();
2628 foreach (LoopItem variantcomb in GetLoop("VariantCombinations").Where(vc => IsProductWebAvailable(vc)))
2629 {
2630 string[] combinations = variantcomb.GetString("Ecom:VariantCombination.VariantID").Split('.');
2631 variantCombinationsObject.Add(combinations);
2632 webAvailableVariantIds.AddRange(combinations);
2633 }
2634
2635 webAvailableVariantIds = webAvailableVariantIds.Distinct().ToList();
2636
2637 string combinationsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantCombinationsObject).Replace("\"", "\'");
2638
2639 var variantGroupsObject = new List<List<String>>();
2640 foreach (LoopItem variantGroup in variantGroups)
2641 {
2642 var variantsObject = new List<String>();
2643 foreach (LoopItem variantOption in variantGroup.GetLoop("VariantAvailableOptions").Where(vao => webAvailableVariantIds.Contains(vao.GetString("Ecom:VariantOption.ID"))))
2644 {
2645 variantsObject.Add(variantOption.GetString("Ecom:VariantOption.ID"));
2646 }
2647 variantGroupsObject.Add(variantsObject);
2648 }
2649
2650 string variantsJson = Newtonsoft.Json.JsonConvert.SerializeObject(variantGroupsObject).Replace("\"", "\'");
2651 string productGroupId = System.Web.HttpContext.Current.Request["GroupId"];
2652
2653 <div>
2654 <div class="js-variants" data-total-variant-groups="@variantGroups.Count" data-combinations="@combinationsJson" data-variants="@variantsJson" data-variant-selections="@variantSelection" data-selection-complete="UpdatePage" data-page-id="@pageId" data-product-id="@productId" data-group-id="@productGroupId">
2655 @foreach (LoopItem variantGroup in variantGroups)
2656 {
2657 var variantAvailableOptions = variantGroup.GetLoop("VariantAvailableOptions").Where(vao => webAvailableVariantIds.Contains(vao.GetString("Ecom:VariantOption.ID")));
2658 var variantsLayout = "";
2659
2660 if (variantAvailableOptions.Any(vao => !String.IsNullOrEmpty(vao.GetString("Ecom:VariantOption.HexColor"))))
2661 {
2662 variantsLayout = "colors";
2663 }
2664 else if (variantAvailableOptions.Any(vao => !String.IsNullOrEmpty(vao.GetString("Ecom:VariantOption.ImgMedium.Clean"))))
2665 {
2666 variantsLayout = "images";
2667 }
2668
2669 string groupId = variantGroup.GetString("Ecom:VariantGroup.ID");
2670
2671 <fieldset>
2672 <legend>@variantGroup.GetString("Ecom:VariantGroup.Name")</legend>
2673 @if (variantsLayout == "colors" || variantsLayout == "images")
2674 {
2675 var selectedVariantOption = variantAvailableOptions.FirstOrDefault(c => c.GetBoolean("Ecom:VariantOption.Selected") && isVariantRequest);
2676 <strong class="bold">@variantGroup.GetString("Ecom:VariantGroup.Name")@String.Format("{0}", selectedVariantOption != null ? string.Concat(": ", selectedVariantOption.GetString("Ecom:VariantOption.Name")) : string.Empty)</strong>
2677 }
2678 <div>
2679 @if (variantsLayout == "colors")
2680 {
2681 foreach (LoopItem variantOption in variantAvailableOptions)
2682 {
2683 string selected = isVariantRequest && variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : "";
2684 string color = variantOption.GetString("Ecom:VariantOption.HexColor");
2685
2686 <button type="button" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-text="@(variantOption.GetString("Ecom:VariantOption.Name"))" data-variant-group="@groupId" onclick="MatchVariants.SelectThis(event)" class="btn btn-colorbox u-margin-right @selected js-variant-option" data-check="@selected" style="background-color: @color"></button>
2687 }
2688 }
2689 else if (variantsLayout == "images")
2690 {
2691 foreach (LoopItem variantOption in variantAvailableOptions)
2692 {
2693 string selected = isVariantRequest && variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : "";
2694 string image = "/Files/" + variantOption.GetString("Ecom:VariantOption.ImgMedium.Clean");
2695
2696 @*START CUSTOM CODE*@
2697 <button type="button" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-text="@(variantOption.GetString("Ecom:VariantOption.Name"))" data-variant-group="@groupId" onclick="MatchVariants.SelectThis(event)" onmouseover="MatchVariants.ImageMouseOver(this)" onmouseout="MatchVariants.ImageMouseOut(this)" class="btn btn-image @selected js-variant-option" data-check="@selected" style="background-image: url('@($"/Admin/Public/GetImage.ashx?image={image}&width=30&Format=WebP&Quality=100")')" data-hover-image="@($"/Admin/Public/GetImage.ashx?image={image}&width=150&Format=WebP&Quality=100")">@variantOption.GetString("Ecom:VariantOption.Name")</button>
2698 @*END CUSTOM CODE*@
2699 }
2700 }
2701 else
2702 {
2703 <select id="VariantSelector_@groupId" class="u-full-width dw-mod" name="VariantSelector_@groupId" onchange="MatchVariants.SelectOnChange(event)" >
2704 <option value="">@Translate("Choose")</option>
2705 @foreach (LoopItem variantOption in variantAvailableOptions)
2706 {
2707 string check = isVariantRequest && variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "checked" : "";
2708 string selected = isVariantRequest && variantOption.GetBoolean("Ecom:VariantOption.Selected") ? "selected" : "";
2709
2710 <option class="js-variant-option @selected" id="@(groupId)
[email protected]("Ecom:VariantOption.ID")" value="@(groupId)
[email protected]("Ecom:VariantOption.ID")" data-variant-id="@variantOption.GetString("Ecom:VariantOption.ID")" data-variant-group="@groupId" @selected data-check="@check">@variantOption.GetString("Ecom:VariantOption.Name")</option>
2711 }
2712 </select>
2713 }
2714 </div>
2715 </fieldset>
2716 }
2717 </div>
2718 </div>
2719 }
2720 }
2721
2722 @helper RenderVariantGroupsCustom(List<LoopItem> loopVariantGroups, bool isVariantRequest)
2723 {
2724 if (loopVariantGroups.Any())
2725 {
2726 if (!isVariantRequest)
2727 {
2728 <b class="col-xs-12 noPadding generalMarginBottom">@Translate("Please select variant below for further details.")</b>
2729 }
2730 if (GetInteger("Ecom:Product.VariantCount") > 0)
2731 {
2732 <div class="col-xs-12 noPadding text-right generalMarginBottom">
2733 @RenderBootstrapButton(new BootstrapButtonSettings
2734 {
2735 Label = Translate("Reset"),
2736 Href = string.Concat("/Default.aspx?ID=", GetGlobalValue("Global:Page.ID").ToString(), "&GroupID=", GetString("Ecom:Group.ID"), "&ProductID=", GetString("Ecom:Product.ID"))
2737 })
2738 </div>
2739 }
2740 <div id="variantsContainer" class="col-xs-12 noPadding">
2741 @RenderRapidoVariantsEngine(isVariantRequest)
2742 </div>
2743 }
2744 }
2745 }@inherits RazorTemplateBase<RazorTemplateModel<Template>>
2746 @using Dynamicweb.Rendering
2747 @using System.Collections.Generic
2748 @using System.Linq
2749 @using System.Web.Script.Serialization
2750 @using Dna.Frontend
2751 @using Dna.Frontend.Forms
2752 @using Dynamicweb.Forms
2753 @functions
2754 {
2755 public string GetProductJsonData()
2756 {
2757
2758 var variantCombinations = GetLoop("VariantCombinations");
2759 var product = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
2760 var variants = new Dictionary<string, Dictionary<string, string>>();
2761
2762 if (!variantCombinations.Any()) return "{}";
2763
2764 foreach (var variant in variantCombinations)
2765 {
2766 var productNumberVariant = variant.GetString("Ecom:Product.Number");
2767 var price = variant.GetString("Ecom:Product.Price");
2768 var stock = variant.GetString("Ecom:Product.AvailableAmount");
2769 var image = variant.GetImagePath();
2770 var id = variant.GetString("Ecom:VariantCombination.VariantID");
2771 var variantName = variant.GetString("Ecom:VariantCombination.VariantText");
2772 var variantDict = new Dictionary<string, string>
2773 {
2774 {"name", variantName},
2775 {"id", id},
2776 {"number", productNumberVariant},
2777 {"price", price},
2778 {"stock", stock},
2779 {"images", GetVariantImages(image, variant.GetString("Ecom:Product:Field.ImageFileNamingPart.Value.Clean"))},
2780 {"productIsFavorite", variant.GetString("Ecom:Product.IsProductInFavoriteList")},
2781 {"addToList", variant.GetString("Ecom:Product.AddToList")},
2782 {"removeFromList", variant.GetString("Ecom:Product.RemoveFromList")}
2783 };
2784
2785 variants.Add(id, variantDict);
2786 }
2787 product.Add("product", variants);
2788
2789 return new JavaScriptSerializer().Serialize(product);
2790 }
2791 }
2792 @{
2793
2794 @helper RenderVariantGroups(List<LoopItem> loopVariantGroups)
2795 {
2796 var renderAsDropdowns = ShowVariantsAsDropdown();
2797
2798 if (loopVariantGroups.Any())
2799 {
2800 <div id="variantsContainer" class="col-xs-12 noPadding">
2801 @RenderField(FieldSettings.CreateHiddenField("variantID", GetString("Ecom:Product.DefaultVariantComboID")))
2802
2803 @foreach (var variantGroup in loopVariantGroups)
2804 {
2805 var variantGroupId = variantGroup.GetString("Ecom:VariantGroup.ID");
2806 var loopAvailableOptions = variantGroup.GetLoop("VariantAvailableOptions");
2807
2808 if (!renderAsDropdowns)
2809 {
2810 @:<div id="@variantGroupId" class="variantRadiosContainer">
2811 <legend>@variantGroup.GetString("Ecom:VariantGroup.Name")</legend>
2812 }
2813 if (loopAvailableOptions.Any())
2814 {
2815 var variantOptions = new List<FieldOption>();
2816 var count = 0;
2817 var availableOptionsFieldSettings = new FieldSettings
2818 {
2819 Type = FieldType.Radio,
2820 SystemName = variantGroupId,
2821 WrapperCssClass = "col-xs-12 noPadding",
2822 IncludeWrapper = true
2823 };
2824
2825 foreach (var option in loopAvailableOptions)
2826 {
2827 var optionId = option.GetString("Ecom:VariantOption.ID");
2828 var optionName = option.GetString("Ecom:VariantOption.Name");
2829 var optionSelected = option.GetBoolean("Ecom:VariantOption.Selected");
2830
2831 variantOptions.Add(new FieldOption
2832 {
2833 Label = optionName,
2834 SystemName = variantGroupId,
2835 Id = variantGroupId + "_" + count++,
2836 Value = optionId,
2837 IsSelected = optionSelected
2838 });
2839 availableOptionsFieldSettings.FieldOptionsList = variantOptions;
2840 }
2841
2842 if (renderAsDropdowns)
2843 {
2844 availableOptionsFieldSettings.Type = FieldType.Select;
2845 availableOptionsFieldSettings.CssClass = "full-width-input";
2846 availableOptionsFieldSettings.WrapperCssClass += " col-sm-6";
2847 }
2848 @RenderField(availableOptionsFieldSettings)
2849
2850 }
2851 if (!renderAsDropdowns)
2852 {
2853 @:</div>
2854 }
2855 }
2856 </div>
2857 }
2858 }
2859
2860 }
2861 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
2862 @using Dynamicweb.Rendering
2863 @using System
2864 @using System.Collections.Generic
2865 @using System.Linq
2866 @using System.Text
2867 @using Dynamicweb.Core
2868 @{
2869 @helper RenderDownloadItemsTab()
2870 {
2871 var loopDetails = GetLoop("Details");
2872 if (loopDetails.Any())
2873 {
2874 const string temp = @".";
2875 const string metafield = "title";
2876
2877 var iconFiles = new Dictionary<string, string>
2878 {
2879 {"pdf", "fa-file-pdf-o"},
2880 {"jpg", "fa-picture-o"},
2881 {"png", "fa-picture-o"},
2882 {"zip", "fa-file-archive-o"},
2883 {"rar", "fa-file-archive-o"}
2884 };
2885 var productDownloadsTab = new StringBuilder("<ul>");
2886 foreach (var detail in loopDetails)
2887 {
2888 var file = detail.GetString("Ecom:Product:Detail.Image.Clean");
2889 var metadata = Dynamicweb.Content.Files.Metadata.EditorFactory.GetMetadataForFile(file);
2890 var fileTitle = metadata != null && metadata.GetValue(metafield).IsNullOrEmpty()
2891 ? metadata.GetValue(metafield)
2892 : Translate("Download");
2893 var substringFile = file.Substring(file.LastIndexOf(temp, StringComparison.Ordinal) + 1,
2894 file.Length - file.LastIndexOf(temp, StringComparison.Ordinal) - 1);
2895 var icon = iconFiles.ContainsKey(substringFile) ? iconFiles[substringFile] : "fa-file-pdf-o";
2896
2897 productDownloadsTab.Append("<li>");
2898 productDownloadsTab.Append("<a class=\"downloadFile\" href=\"" + file + "\">");
2899 productDownloadsTab.Append(GetIcon(icon, fileTitle));
2900 productDownloadsTab.Append("</a>");
2901 productDownloadsTab.Append("</li>");
2902 }
2903 productDownloadsTab.Append("</ul>");
2904 @RenderTabContent("productDownloads_tab", string.Concat(Translate("Downloads"), " (products)"), productDownloadsTab.ToString())
2905 }
2906 }
2907 }
2908 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
2909 @using System
2910 @using Dynamicweb.Rendering
2911 @using System.Linq
2912 @using Dna.UrlServices
2913 @using Dynamicweb.Frontend
2914
2915 @functions
2916 {
2917 public int GetParagraphIdFromCc()
2918 {
2919 var sendOrderPageId = GetPageIdByNavigationTag("SendOrder");
2920 var paragraphCollection = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(sendOrderPageId);
2921 var paragraphId = paragraphCollection != null ? paragraphCollection.Where(p => p.ModuleSystemName == "eCom_CustomerCenter" && p.ShowParagraph).Select(p => p.ID).FirstOrDefault() : 0;
2922
2923 return paragraphId;
2924 }
2925
2926 public bool IsProductOrderable(LoopItem product = null)
2927 {
2928 return IsProductStatus("Orderable", product);
2929 }
2930
2931 public bool IsProductVisible(LoopItem product = null)
2932 {
2933 return IsProductStatus("Visible", product);
2934 }
2935
2936 public bool IsProductWebAvailable(LoopItem product = null)
2937 {
2938 return IsProductOrderable(product) || IsProductVisible(product);
2939 }
2940
2941 public bool IsProductStatus(string fieldValue, LoopItem product = null)
2942 {
2943 var user = Pageview.User;
2944 var customerType = user != null ? user.CustomFieldValues.First(fv => fv.CustomField.SystemName == "AccessUser_CustomerType").Value.ToString() : "";
2945 var defaultSettings = Pageview.Area.Item["AnonymousCustomerType"];
2946 var anonymousUser = user == null && defaultSettings != null ? defaultSettings.ToString() : "";
2947
2948 var productB2BStatus = product != null ? product.GetString("Ecom:Product:Field.B2BStatus.Value") : GetString("Ecom:Product:Field.B2BStatus.Value");
2949 var productB2BEligible = product != null ? product.GetString("Ecom:Product:Field.B2BLegEligibleStatus.Value") : GetString("Ecom:Product:Field.B2BLegEligibleStatus.Value");
2950 var productGLMPStatus = product != null ? product.GetString("Ecom:Product:Field.GLMPStatus.Value") : GetString("Ecom:Product:Field.GLMPStatus.Value");
2951 var productB2CStatus = product != null ? product.GetString("Ecom:Product:Field.B2CStatus.Value") : GetString("Ecom:Product:Field.B2CStatus.Value");
2952 var productB2CBoatlifter = product != null ? product.GetString("Ecom:Product:Field.B2CBoatlifterStatus.Value") : GetString("Ecom:Product:Field.B2CBoatlifterStatus.Value");
2953
2954 var userB2B = (anonymousUser == "B2B" || customerType == "B2B") && productB2BStatus.Equals(fieldValue);
2955 var userB2BLegEligible = (anonymousUser == "B2BLegEligible" || customerType == "B2BLegEligible") && productB2BEligible.Equals(fieldValue);
2956 var userGlmp = (anonymousUser == "GLMP" || customerType == "GLMP") && productGLMPStatus.Equals(fieldValue);
2957 var userB2C = (anonymousUser == "B2C" || customerType == "B2C") && productB2CStatus.Equals(fieldValue);
2958 var userB2CBoatLifter = (anonymousUser == "B2CBoatlifter" || customerType == "B2CBoatlifter") && productB2CBoatlifter.Equals(fieldValue);
2959
2960 return userB2B || userB2BLegEligible || userB2C || userGlmp || userB2CBoatLifter;
2961 }
2962
2963 public bool IsBoatlifterSite()
2964 {
2965 var websites = "";
2966 try
2967 {
2968 websites = Pageview.Area.Item["Websites"].ToString();
2969 }
2970 catch(Exception e)
2971 {
2972 websites = "Standard"; // temp workaround
2973 }
2974
2975 return websites == "Boatlifter";
2976 }
2977
2978 public string GetWebsiteDomain(PageView pageview)
2979 {
2980 return Dna.Hewitt.Helpers.GetWebsiteDomain(pageview);
2981 }
2982 }
2983
2984 @helper RenderIFrameContent()
2985 {
2986 @GetString("Item.IFrame")
2987 }
2988 @helper RenderUserIsBlockedMessage()
2989 {
2990 <div class="homeAccountError">
2991 <h2>@Translate("Account is blocked, please contact Customer Service (800) 544-2067")</h2>
2992 </div>
2993 }@inherits RazorTemplateBase<RazorTemplateModel<Template>>
2994 @using System
2995 @using Dynamicweb.Rendering
2996 @using System.Collections.Generic
2997 @using System.Linq
2998 @using System.Text.RegularExpressions
2999 @using Dna.Frontend
3000 @using Dna.Frontend.UI
3001 @using Dynamicweb.Core
3002 @using System.Data
3003 @functions
3004 {
3005 public List<Tuple<string,string,FileType>> GetVariantImagesCustom(string defaultMedia, string fileNamingPart, string defaultName = "")
3006 {
3007 if (defaultMedia.IsNullOrEmpty()) return new List<Tuple<string,string,FileType>>();
3008 var pattern = Pageview.Area.Item["Multiple_ProductImagesCharacter"] + "*";
3009 var fileName = string.Concat(defaultMedia.Replace(Images.GetProductImageFolder(), string.Empty, RegexOptions.IgnoreCase).Replace(".jpg", string.Empty), pattern);
3010 var mediaList = (List<Tuple<string,string,FileType>>) GetMediaFilesInFolder(defaultMedia, fileName, defaultName);
3011
3012 fileNamingPart = StringHelpers.SanitizeFileName(fileNamingPart) + Pageview.Area.Item["Multiple_ProductImagesCharacter"] + "*";
3013 mediaList.AddRange(GetMediaFilesInFolder(defaultMedia, fileNamingPart, defaultName, false));
3014
3015 return mediaList.Distinct().ToList();
3016 }
3017
3018 public string GetProductWarranty(string warrantyId)
3019 {
3020 if (warrantyId.IsNotNullOrEmpty())
3021 {
3022 var cmdBuilder = Dynamicweb.Data.CommandBuilder.Create(string.Format(@"SELECT TOP 1 WarrantyText FROM ItemType_Warranty_Text wt
3023 INNER JOIN Paragraph p
3024 ON p.ParagraphItemType = 'Warranty_Text' AND wt.Id = p.ParagraphItemId AND p.ParagraphShowParagraph=1
3025 INNER JOIN Page pg
3026 ON p.ParagraphPageID=pg.PageID AND pg.PageAreaID='{0}'
3027 WHERE WarrantyId = '{1}'", Pageview.Area.ID, warrantyId));
3028
3029 var value = Dynamicweb.Data.Database.ExecuteScalar(cmdBuilder);
3030
3031 if (value != null)
3032 {
3033 return value.ToString();
3034 }
3035 }
3036
3037 return string.Empty;
3038 }
3039
3040 public Dictionary<string, string> GetProductWarranty(List<string> warrantyId)
3041 {
3042 var result = new Dictionary<string, string>();
3043
3044 if (warrantyId.Any())
3045 {
3046 var cmdBuilder = Dynamicweb.Data.CommandBuilder.Create(string.Format(@"SELECT WarrantyId, WarrantyText FROM ItemType_Warranty_Text wt
3047 INNER JOIN Paragraph p
3048 ON p.ParagraphItemType = 'Warranty_Text' AND wt.Id = p.ParagraphItemId AND p.ParagraphShowParagraph=1
3049 INNER JOIN Page pg
3050 ON p.ParagraphPageID=pg.PageID AND pg.PageAreaID='{0}'
3051 WHERE WarrantyId IN ('{1}')", Pageview.Area.ID, string.Join("','", warrantyId)));
3052
3053 var reader = Dynamicweb.Data.Database.CreateDataReader(cmdBuilder);
3054
3055 while (reader.Read())
3056 {
3057 if (!result.ContainsKey(reader.GetString(0)))
3058 {
3059 result.Add(reader.GetString(0), reader.GetString(1));
3060 }
3061 }
3062 }
3063
3064 return result;
3065 }
3066
3067 public string GetProductMeasurement(string measurementId)
3068 {
3069 if (measurementId.IsNotNullOrEmpty())
3070 {
3071 var cmdBuilder = Dynamicweb.Data.CommandBuilder.Create(string.Format(@"SELECT TOP 1 MeasurementText FROM ItemType_MeasurementContent mc
3072 INNER JOIN Paragraph p
3073 ON p.ParagraphItemType = 'MeasurementContent' AND mc.Id = p.ParagraphItemId AND p.ParagraphShowParagraph=1
3074 INNER JOIN Page pg
3075 ON p.ParagraphPageID=pg.PageID AND pg.PageAreaID='{0}'
3076 WHERE MeasurementId = '{1}'", Pageview.Area.ID, measurementId));
3077
3078 var value = Dynamicweb.Data.Database.ExecuteScalar(cmdBuilder);
3079
3080 if (value != null)
3081 {
3082 return value.ToString();
3083 }
3084 }
3085
3086 return string.Empty;
3087 }
3088
3089 public Dictionary<string, string> GetProductMeasurement(List<string> measurementIds)
3090 {
3091 var result = new Dictionary<string, string>();
3092
3093 if (measurementIds.Any())
3094 {
3095 Dynamicweb.Data.CommandBuilder.Create("");
3096
3097 var cmdBuilder = Dynamicweb.Data.CommandBuilder.Create(string.Format(@"SELECT MeasurementId, MeasurementText FROM ItemType_MeasurementContent mc
3098 INNER JOIN Paragraph p
3099 ON p.ParagraphItemType = 'MeasurementContent' AND mc.Id = p.ParagraphItemId AND p.ParagraphShowParagraph=1
3100 INNER JOIN Page pg
3101 ON p.ParagraphPageID=pg.PageID AND pg.PageAreaID='{0}'
3102 WHERE MeasurementId IN ('{1}')", Pageview.Area.ID, string.Join("','", measurementIds)));
3103
3104 var reader = Dynamicweb.Data.Database.CreateDataReader(cmdBuilder);
3105
3106 while (reader.Read())
3107 {
3108 if (!result.ContainsKey(reader.GetString(0)))
3109 {
3110 result.Add(reader.GetString(0), reader.GetString(1));
3111 }
3112 }
3113 }
3114
3115 return result;
3116 }
3117 }
3118 @{
3119 @helper RenderVideosTab()
3120 {
3121 @InternalRenderTabHeader("#videos_tab", Translate("Videos"), "productvideos_tab hidden")
3122 <div class="col-xs-12 productVideos" id="videos_tab"></div>
3123 }
3124
3125 @helper RenderDownloadItemsTabCustom()
3126 {
3127 var loopDetails = GetLoop("Details");
3128 if (loopDetails.Any())
3129 {
3130 const string temp = @".";
3131 const string metafield = "title";
3132
3133 var iconFiles = new Dictionary<string, string>
3134 {
3135 {"pdf", "fa-file-pdf-o"},
3136 {"jpg", "fa-picture-o"},
3137 {"png", "fa-picture-o"},
3138 {"zip", "fa-file-archive-o"},
3139 {"rar", "fa-file-archive-o"}
3140 };
3141 var productDownloadsTab = new StringBuilder("<ul>");
3142 foreach (var detail in loopDetails)
3143 {
3144 var file = detail.GetString("Ecom:Product:Detail.Image.Clean");
3145 var metadata = Dynamicweb.Content.Files.Metadata.EditorFactory.GetMetadataForFile(file);
3146 var fileTitle = metadata != null && metadata.GetValue(metafield).IsNullOrEmpty()
3147 ? metadata.GetValue(metafield)
3148 : Translate("Download");
3149 var substringFile = file.Substring(file.LastIndexOf(temp, StringComparison.Ordinal) + 1,
3150 file.Length - file.LastIndexOf(temp, StringComparison.Ordinal) - 1);
3151 var icon = iconFiles.ContainsKey(substringFile) ? iconFiles[substringFile] : "fa-file-pdf-o";
3152
3153 productDownloadsTab.Append("<li>");
3154 productDownloadsTab.Append("<a class=\"downloadFile\" href=\"" + file + "\" download>");
3155 productDownloadsTab.Append(GetIcon(icon, fileTitle));
3156 productDownloadsTab.Append("</a>");
3157 productDownloadsTab.Append("</li>");
3158 }
3159 productDownloadsTab.Append("</ul>");
3160 @RenderTabContent("productDownloads_tab", string.Concat(Translate("Downloads"), " (products)"), productDownloadsTab.ToString())
3161 }
3162 }
3163 @helper RenderProductThumbnailsCustom(string defaultMedia, string fileNamingPart, string defaultName = "")
3164 {
3165 var mediaList = GetVariantImagesCustom(defaultMedia, fileNamingPart, defaultName);
3166
3167 <div id="imgThumbs" class="col-xs-12 noPaddingLeft hidden">
3168 <ul>
3169 @foreach (var imageStr in mediaList)
3170 {
3171 @InternalRenderProductThumbnailItem(imageStr)
3172 }
3173 </ul>
3174 </div>
3175 }
3176 }@{
3177 @helper RenderQuantityPricesCustom()
3178 {
3179 if (Pageview.Area.Item["ShowQuantityField"].ToString() == "True")
3180 {
3181 <div id="pricesContainer" class="col-xs-12 noPaddingLeft topMargin20 generalMarginBottom hiddenAtStart hidden">
3182 <legend>@Translate("Quantity Prices")</legend>
3183 <ul id="quantityContainer"></ul>
3184 </div>
3185 }
3186 }
3187 }
3188 @functions
3189 {
3190 private string GetQuantityPricesHtml(List<LoopItem> loopProdPrices)
3191 {
3192 var qtyPrefix = Translate("Qty");
3193 var loopCount = loopProdPrices.Count;
3194 var count = 1;
3195 var result = new StringBuilder();
3196
3197 if (loopCount == 1)
3198 {
3199 return string.Empty;
3200 }
3201
3202 foreach (var price in loopProdPrices)
3203 {
3204 var quantity = price.GetInteger("Ecom:Product.Prices.Quantity").Equals(0) ? 1 : price.GetInteger("Ecom:Product.Prices.Quantity");
3205 var priceProd = price.GetString("Ecom:Product.Prices.PriceWithoutVATFormatted");
3206 var nextQty = count < loopCount ? loopProdPrices[count].GetInteger("Ecom:Product.Prices.Quantity") : loopProdPrices[count-1].GetInteger("Ecom:Product.Prices.Quantity");
3207 var priceQtyLabel = quantity == nextQty-1 ? string.Concat(qtyPrefix," ", quantity) : quantity != nextQty ? string.Concat(qtyPrefix, " ", quantity, " - ", nextQty - 1) : string.Concat(qtyPrefix, " ", quantity," ", Translate(" or more"));
3208 nextQty = quantity == nextQty ? 999999 : nextQty;
3209
3210 result.AppendFormat("<li class='qtyPrice' data-min='{0}' data-max='{1}' data-price='{2}'><strong class='col-xs-6 noPaddingLeft'>{3}</strong><strong class='col-xs-6 noPaddingRight text-right'>{2}</strong></li>",
3211 quantity, nextQty - 1, priceProd, priceQtyLabel);
3212
3213 count++;
3214 }
3215 return result.ToString();
3216 }
3217 }
3218 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
3219 @using System
3220 @using Dynamicweb.Rendering
3221 @using System.Collections.Generic
3222 @using System.Data
3223 @using System.Globalization
3224 @using System.Linq
3225 @using System.Text
3226 @using Dna.Frontend.Forms
3227 @using Dynamicweb.Content
3228 @using Dynamicweb.Core
3229 @using Dna.Frontend.UI
3230 @using Dynamicweb.Forms
3231
3232 @functions
3233 {
3234
3235 public DataRow[] GetStoresFromDb()
3236 {
3237 var page = Dynamicweb.Extensibility.ServiceLocator.Current.GetPageService().GetPage(GetPageIdByNavigationTag("GeneralSettings"));
3238 var generalSettings = Dynamicweb.Content.Items.Item.GetItemById(page.ItemType, page.ItemId);
3239
3240 var dealerGroups = generalSettings["DealerGroups"].ToString();
3241 var storesGroupId = dealerGroups.IsNotNullOrEmpty() ? "%" + dealerGroups + "%" : string.Empty;
3242 // TODO - Find a new way to pass the storesGroupId
3243 var command = Dynamicweb.Data.CommandBuilder.Create(
3244 @"SELECT AccessUserState, AccessUserCountry, AccessUserZip, AccessUserAddress, AccessUserName, AccessUserCity, AccessUserGeoLocationLat, AccessUserImage, AccessUserGeoLocationLng
3245 FROM accessUser WHERE AccessUserCountry is not NULL AND AccessUserCountry != '' AND AccessUserGeoLocationLat IS NOT NULL AND AccessUserGroups LIKE '"+storesGroupId+"'");
3246 using (var storesDataSet = Dynamicweb.Data.Database.CreateDataSet(command))
3247 {
3248 return storesDataSet.Tables[0].Select();
3249 }
3250
3251 }
3252
3253 public List<string> GetCountriesFromDbUsers(IEnumerable<DataRow> stores)
3254 {
3255 var countries = stores.Select(r => r["AccessUserCountry"].ToString().Trim()).Distinct().ToList();
3256
3257 return countries;
3258 }
3259
3260 public DataRow[] GetRegionsDataSet()
3261 {
3262 const string accessRegionsDataSql = "SELECT CountryTextName, CountryTextCode2, CountryTextRegionCode FROM EcomCountryText";
3263 using (var regionsDataSet = Dynamicweb.Data.Database.CreateDataSet(accessRegionsDataSql))
3264 {
3265 return regionsDataSet.Tables[0].Select();
3266 }
3267 }
3268
3269 public string GetCountriesAndRegionsFromDbUsers(IEnumerable<string> countries, DataRow[] storesDataSet, DataRow[] regionsDataSet)
3270 {
3271 var regionsJson = new StringBuilder("{");
3272 foreach (var country in countries)
3273 {
3274 var regionsWithStores = storesDataSet.Where(r => (string) r["AccessUserCountry"] == country).Select(r => ((string) r["AccessUserState"]).Trim()).Distinct().ToList();
3275 var countNum = 0;
3276
3277 if (regionsJson.ToString() != "{")
3278 {
3279 regionsJson.Append(",");
3280 }
3281 regionsJson.Append("\"" + country + "\":[");
3282
3283
3284 foreach (var region in regionsWithStores)
3285 {
3286 var regionText = string.Empty;
3287
3288 if(region.IsNotNullOrEmpty() || regionsDataSet.Any())
3289 {
3290
3291 var regionDataSet = regionsDataSet.FirstOrDefault(r => r["CountryTextRegionCode"].ToString() == region.ToString());
3292 regionText = regionDataSet != null ? regionDataSet["CountryTextName"].ToString() : string.Empty;
3293 }
3294
3295 if (regionText.IsNullOrEmpty()) continue;
3296 if (countNum != 0)
3297 {
3298 regionsJson.Append(",");
3299 }
3300 regionsJson.Append("\"" + regionText + "\"");
3301 countNum++;
3302 }
3303 regionsJson.Append("]");
3304 }
3305 regionsJson.Append("}");
3306
3307 return regionsJson.ToString();
3308 }
3309
3310 }
3311 @{
3312
3313 @helper RenderStoresMap(DataRow[] stores, DataRow[] regions, bool hasZipCode = false)
3314 {
3315 <div id="loading" class="col-xs-12"> </div>
3316 <div class="map col-sm-8 col-xs-12 noPaddingLeft">
3317 <div id="Maps-85-map"></div>
3318 </div>
3319 <div class="list col-sm-4 col-xs-12">
3320 <div class="no-matches hidden">@Translate("No locations found")</div>
3321 @if (stores != null && regions != null)
3322 {
3323 <ol class="storeList" id="Maps-85-list" data-sort-order="desc">
3324 @foreach (var store in stores)
3325 {
3326 var regionTextList = regions.FirstOrDefault(r => r["CountryTextRegionCode"].ToString() == store["AccessUserState"].ToString());
3327 var regionTextString = regionTextList != null ? regionTextList["CountryTextName"].ToString() : string.Empty;
3328 var userZip = store["AccessUserZip"];
3329 var dateLat = Convert.ToDecimal(store["AccessUserGeoLocationLat"]).ToString(CultureInfo.InvariantCulture);
3330 var dateLng = Convert.ToDecimal(store["AccessUserGeoLocationLng"]).ToString(CultureInfo.InvariantCulture);
3331 var dateTitel = store["AccessUserName"];
3332 var dateCountry = store["AccessUserCountry"];
3333 var dateCityCode = store["AccessUserState"];
3334 var dataSortValue = store["AccessUserName"];
3335
3336 <li data-zip="@userZip" data-lat="@dateLat" data-lng="@dateLng" data-title="@dateTitel" data-filter-values="" data-country="@dateCountry" data-citycode="@dateCityCode" data-city="@regionTextString" data-sort-value="@dataSortValue">
3337 <div>
3338 <h3>@store["AccessUserName"]</h3>
3339 @GetAddressFormatted(
3340 store["AccessUserAddress"].ToString(),
3341 string.Empty,
3342 store["AccessUserCity"].ToString(),
3343 store["AccessUserZip"].ToString(),
3344 store["AccessUserState"].ToString(),
3345 string.Empty,
3346 false,
3347 true,
3348 true,
3349 "<br/>"
3350 )
3351 </div>
3352 </li>
3353 }
3354 </ol>
3355 }
3356 @Translate("Please contact your authorized dealer to purchase products.")
3357 </div>
3358 @SnippetStart("outScripts")
3359 <script type="text/javascript" src="//maps.googleapis.com/maps/api/js?v=3&libraries=geometry&key=AIzaSyCPqixQl_pI1tO7DRIS-9LatrY_dtGLHww"></script>
3360 @*START CUSTOM CODE*@
3361 var mapsJsFileSrc = $"{GetString("Template:DesignBaseUrl")}/Maps/javascripts/Maps.js";
3362 var mapsJsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath(mapsJsFileSrc));
3363
3364 <script type="text/javascript" src="@(mapsJsFileSrc)?@(mapsJsFileInfo.LastWriteTime.Ticks)"></script>
3365 @*END CUSTOM CODE*@
3366 @SnippetEnd("outScripts")
3367 }
3368 @*
3369 @helper RenderStoresJavascriptArray(DataRow[] stores)
3370 {
3371 @: var arr_stores = [];
3372 var displayLimit = 0;
3373 foreach (var store in stores)
3374 {
3375 displayLimit++;
3376 if (displayLimit == 3)
3377 {
3378 break;
3379 }
3380 var urlToDesignsFolder = string.Concat(Helpers.GetCurrentUrl(true), "/Files/Templates/Designs/", Pageview.Area.Layout.Design.Name, "/");
3381 <text>
3382 arr_stores.push({
3383 marker_title:'@store["AccessUserName"]',
3384 marker_zip:'@store["AccessUserZip"]',
3385 marker_latlng:'@string.Concat(store["AccessUserGeoLocationLat"].ToString(), ",", store["AccessUserGeoLocationLng"].ToString())',
3386 marker_icon:{
3387 image:'@string.Concat(urlToDesignsFolder, "images/gmap/pointer.png")',
3388 width:54, height:65,
3389 originX:0, originY:0,
3390 anchorX:27, anchorY:65
3391 },
3392 marker_infoText:"@GetAddressFormatted(
3393 store["AccessUserAddress"].ToString(),
3394 string.Empty,
3395 store["AccessUserCity"].ToString(),
3396 store["AccessUserZip"].ToString(),
3397 store["AccessUserState"].ToString(),
3398 string.Empty,
3399 false,
3400 true,
3401 true,
3402 "<br/>"
3403 )"
3404 });
3405 </text>
3406 }
3407 }
3408 *@
3409
3410 @helper RenderCountriesDropdown(List<string> countriesList = null, bool includeWrapper = false)
3411 {
3412 var settings = new FieldSettings
3413 {
3414 SystemName = "country",
3415 Id = "country",
3416 Label = Translate("Select your country"),
3417 IncludeWrapper = includeWrapper
3418 };
3419
3420 if (countriesList != null)
3421 {
3422 settings.ValuesList = countriesList;
3423 }
3424
3425 @RenderCountriesDropdownField(settings, false, false, false)
3426 }
3427 @helper RenderHeaderForZipcode(List<string> countries)
3428 {
3429 <form class="search">
3430 @RenderField(new FieldSettings
3431 {
3432 Label = Translate("Zip Code"),
3433 Type = FieldType.Text,
3434 SystemName = "zip",
3435 Id = "zipcode",
3436 WrapperCssClass = "col-sm-3 col-xs-12",
3437 IsRequired = true,
3438 IncludeWrapper = true
3439 })
3440
3441 <fieldset class="col-sm-3 col-xs-12 noPaddingLeft">
3442 @RenderCountriesDropdown(countries, true)
3443 </fieldset>
3444 <fieldset id="dealerType" class="Radio col-md-3 col-sm-4 col-xs-12 noPadding">
3445 <div class="Radio">
3446 <label class="form-label">@Translate("Dealer Option")</label>
3447 @{
3448 var dealerTypes = new FieldSettings {Type = FieldType.Radio};
3449 dealerTypes.FieldOptionsList.Add(new FieldOption
3450 {
3451 Label = "Authorized Hewitt Dealers",
3452 Value = "hewittDealerType1",
3453 SystemName = "HewittDealerType",
3454 IsSelected = true
3455 }
3456 );
3457 dealerTypes.FieldOptionsList.Add(new FieldOption
3458 {
3459 Label = "Authorized Pontoon Legs Dealers",
3460 Value = "hewittDealerType2",
3461 SystemName = "HewittDealerType",
3462 IsSelected = false
3463 }
3464 );
3465 }
3466 @RenderField(dealerTypes)
3467 </div>
3468 </fieldset>
3469 <div class="col-xs-12 col-sm-2 col-md-3">
3470 @RenderBootstrapButton(new BootstrapButtonSettings {Label = Translate("Find Dealers"), ButtonType = BootstrapButtonSettings.BootstrapButtonType.Button, Attributes = new Dictionary<string, string> {{"data-search", Translate("nearest")}}})
3471 @RenderBootstrapButton(new BootstrapButtonSettings {Label = Translate("Show all locations"), CssClass = "show-all-locations hidden", ButtonType = BootstrapButtonSettings.BootstrapButtonType.Button, Attributes = new Dictionary<string, string> {{"type", "button"}}})
3472 </div>
3473 </form>
3474 }
3475
3476 @helper RenderHeaderForCountries(List<string> countries)
3477 {
3478 <fieldset class="col-sm-3 col-xs-12 noPaddingLeft">
3479 @RenderCountriesDropdown(countries, true)
3480 </fieldset>
3481 @RenderField(new FieldSettings{Type = FieldType.Select, SystemName = "locality", Label = Translate("Select your region:"), IncludeWrapper = true, WrapperCssClass = "col-sm-3 col-xs-12 regions", FirstHardcodedOptionLabel = Translate("All")})
3482 }
3483
3484 @helper RenderStoresContent(DataRow[] stores, DataRow[] regions, List<string> countries = null)
3485 {
3486 var attrLAbel = countries == null ? string.Empty : string.Concat("data-label='", Translate("Select your "), "'");
3487 <a onclick="findADealerPopup()" style="cursor:pointer">Find A Dealer Popup</a>
3488 <div class="dynamicweb-map" id="Maps-85" data-list-position="hidden" @attrLAbel>
3489 <div class="col-xs-12" id="findStoreFilter">
3490 @RenderHeaderForZipcode(countries)
3491 </div>
3492
3493 @if(countries != null) {
3494 <div class="locations-filter hidden">
3495 @RenderBootstrapButton(new BootstrapButtonSettings {Label = Translate("Search"), ButtonType = BootstrapButtonSettings.BootstrapButtonType.Button, Attributes = new Dictionary<string, string> {{"data-filter-value", Translate("Search")}}})
3496 </div>
3497 }
3498
3499 @RenderStoresMap(stores, regions)
3500 </div>
3501 }
3502
3503 }@inherits RazorTemplateBase<RazorTemplateModel<Template>>
3504 @using System
3505 @using Dynamicweb.Rendering
3506 @using System.Collections.Generic
3507 @using System.Data
3508 @using System.Globalization
3509 @using System.Linq
3510 @using Dna.Frontend.Forms
3511 @using Dynamicweb.Content
3512 @using Dynamicweb.Core
3513 @using Dna.Frontend.UI
3514 @using Dynamicweb.Forms
3515
3516 @functions
3517 {
3518 public string[] GetStoresGroupId()
3519 {
3520 var page = Dynamicweb.Extensibility.ServiceLocator.Current.GetPageService().GetPage(GetPageIdByNavigationTag("GeneralSettings"));
3521 var generalSettings = Dynamicweb.Content.Items.Item.GetItemById(page.ItemType, page.ItemId);
3522
3523 var dealerGroups = generalSettings["DealerGroups"].ToString().Split(new[]{','});
3524
3525 return dealerGroups;
3526 }
3527
3528 public DataRow[] GetStoresFromDbCustom()
3529 {
3530 var cacheKey = "StoresList";
3531
3532 if (Dynamicweb.Context.Current?.Session?[cacheKey] != null)
3533 {
3534 return (DataRow[]) Dynamicweb.Context.Current.Session[cacheKey];
3535 }
3536
3537 var dealerGroups = GetStoresGroupId();
3538 var storesSqlFilter = string.Empty;
3539
3540 foreach (var dealerGroup in dealerGroups)
3541 {
3542 storesSqlFilter += storesSqlFilter.IsNotNullOrEmpty() ? " OR " : string.Empty;
3543 storesSqlFilter += "AccessUserGroups LIKE '%" + dealerGroup + "%'";
3544 }
3545
3546 storesSqlFilter = storesSqlFilter.IsNotNullOrEmpty() ? storesSqlFilter : "AccessUserGroups LIKE ''";
3547
3548 DataRow[] storeList;
3549
3550 var command = Dynamicweb.Data.CommandBuilder.Create(
3551 @"SELECT AccessUserId, AccessUserState, AccessUserCountry, AccessUserZip, AccessUserAddress, AccessUserName, AccessUserCity, AccessUserGeoLocationLat, AccessUserImage, AccessUserGeoLocationLng, AccessUser_DealerType, AccessUserPhone, AccessUserEmail, AccessUser_Website
3552 FROM accessUser
3553 WHERE LEN(ISNULL(AccessUserCountry, '')) > 0
3554 AND ISNULL(AccessUserGeoLocationLat, 0)<>0
3555 AND ISNULL(AccessUserGeoLocationLng, 0) <> 0
3556 AND (" + storesSqlFilter + ")");
3557
3558 using (var storesDataSet = Dynamicweb.Data.Database.CreateDataSet(command))
3559 {
3560 storeList = storesDataSet.Tables[0].Select();
3561 }
3562
3563 if (Dynamicweb.Context.Current?.Session != null)
3564 {
3565 Dynamicweb.Context.Current.Session[cacheKey] = storeList;
3566 }
3567
3568 return storeList;
3569 }
3570 }
3571
3572 @{
3573 @helper RenderHeaderForZipcodeCustom()
3574 {
3575 var groupId = GetStoresGroupId();
3576 var userGroup = Dynamicweb.Security.UserManagement.Group.GetGroupByID(Converter.ToInt32(groupId.FirstOrDefault()));
3577 var userSubGroups = userGroup.Subgroups.OrderBy(g => Converter.ToInt32(g.CustomFieldValues.FirstOrDefault(f => f.CustomField.SystemName.Equals("AccessUser_SortOrder"))?.Value)).ToList();
3578 var groupIconPath = "/Files/";
3579
3580 <form id="MapSearch" class="search padding-bottom-1em">
3581 @RenderField(new FieldSettings
3582 {
3583 Label = Translate("Zip Code"),
3584 Type = FieldType.Text,
3585 SystemName = "zip",
3586 Id = "MapSearchField",
3587 WrapperCssClass = "col-md-4 col-xs-12 noPaddingLeft",
3588 IsRequired = false,
3589 IncludeWrapper = true
3590 })
3591
3592 @RenderBootstrapButton(new BootstrapButtonSettings
3593 {
3594 Label = Translate("Find Dealers"),
3595 Id = "MapSearchButton",
3596 ButtonType = BootstrapButtonSettings.BootstrapButtonType.Button,
3597 CssClass = "btn-default action-button",
3598 Attributes = new Dictionary<string, string>
3599 {
3600 {"type", "submit"}
3601 }
3602 })
3603
3604 @RenderBootstrapButton(new BootstrapButtonSettings
3605 {
3606 Label = Translate("Reset Filters"),
3607 ButtonType = BootstrapButtonSettings.BootstrapButtonType.Button,
3608 CssClass = "btn-default action-button",
3609 Attributes = new Dictionary<string, string>
3610 {
3611 {"onclick", "ResetFilters();"},
3612 {"type", "button"}
3613 }
3614 })
3615 </form>
3616
3617 <input type="hidden" id="GroupFilter"/>
3618
3619 <div class="padding-top-and-bottom-1em js-map-filter-column">
3620 <div class="col-12" id="FilterContainer">
3621 @if (userSubGroups.Any())
3622 {
3623 var totalGroups = userSubGroups.Count;
3624
3625 foreach (var subGroup in userSubGroups)
3626 {
3627 var buttonIcon = subGroup.CustomFieldValues.FirstOrDefault(x => x.CustomField.SystemName.Equals("AccessUser_ProductLineIcon", StringComparison.InvariantCultureIgnoreCase))?.Value.ToString();
3628 var description = subGroup.CustomFieldValues.FirstOrDefault(x => x.CustomField.SystemName.Equals("AccessUser_Description", StringComparison.InvariantCultureIgnoreCase))?.Value.ToString();
3629
3630 @RenderBootstrapButton(new BootstrapButtonSettings
3631 {
3632 Label = "<span class=\"group-image-container\">" + @ReadFile(groupIconPath + buttonIcon) + "</span>" + subGroup.Name + (!string.IsNullOrEmpty(description) ? "<span class=\"tooltip-text\">" + description + "</span>" : ""),
3633 ButtonType = BootstrapButtonSettings.BootstrapButtonType.Button,
3634 IconPosition = IconPosition.Left,
3635 CssClass = "btn-default group-button map-filter",
3636 Attributes = new Dictionary<string, string>
3637 {
3638 {"onclick", "ToggleFilters(event, this, '" + subGroup.ID + "');"},
3639 {"style", "z-index: " + totalGroups + ";"}
3640 }
3641 })
3642
3643 totalGroups--;
3644 }
3645 }
3646 </div>
3647 </div>
3648 }
3649
3650 @helper RenderStoresMapCustom(DataRow[] stores)
3651 {
3652 var page = Dynamicweb.Extensibility.ServiceLocator.Current.GetPageService().GetPage(GetPageIdByNavigationTag("GeneralSettings"));
3653 var generalSettings = Dynamicweb.Content.Items.Item.GetItemById(page.ItemType, page.ItemId);
3654 var groupIconPath = "/Files/";
3655
3656 <div class="map col-sm-8 col-xs-12 noPaddingLeft">
3657 <div id="Maps-85-map"></div>
3658 </div>
3659 <div class="list col-sm-4 col-xs-12">
3660 <div class="no-matches hidden">@Translate("No locations found")</div>
3661
3662 @if (stores != null)
3663 {
3664 <ol class="storeList" id="Maps-85-list" data-sort-order="desc" >
3665 @foreach (var store in stores)
3666 {
3667 var lat = Convert.ToDecimal(store["AccessUserGeoLocationLat"]).ToString(CultureInfo.InvariantCulture);
3668 var lng = Convert.ToDecimal(store["AccessUserGeoLocationLng"]).ToString(CultureInfo.InvariantCulture);
3669 var name = store["AccessUserName"].ToString();
3670 var address = store["AccessUserAddress"].ToString();
3671 var city = store["AccessUserCity"].ToString();
3672 var state = store["AccessUserState"].ToString();
3673 var zip = store["AccessUserZip"].ToString();
3674 var country = store["AccessUserCountry"].ToString();
3675 var userName = store["AccessUserName"].ToString();
3676 var phone = store["AccessUserPhone"].ToString();
3677 var email = store["AccessUserEmail"].ToString();
3678 var website = store["AccessUser_Website"].ToString();
3679 var userId = store["AccessUserId"].ToString();
3680
3681 if (!string.IsNullOrEmpty(website) && !website.StartsWith("http"))
3682 {
3683 website = "http://" + website;
3684 }
3685
3686 var directionsLink = "https://www.google.com/maps/dir/?api=1&destination=" + address + "+" + city + "+" + state + "+" + zip;
3687
3688 var user = Dynamicweb.Security.UserManagement.User.GetUserByID(Converter.ToInt32(userId));
3689 var userGroups = string.Join(",", user.GroupsIds);
3690
3691 <li data-zip="@zip" data-lat="@lat" data-lng="@lng" data-title="@name" data-filter-values="" data-country="@country" data-citycode="@state" data-sort-value="@userName" data-user-groups="@(userGroups)">
3692 <div>
3693 <h3>@store["AccessUserName"]</h3>
3694 <p>
3695 @GetAddressFormatted(
3696 store["AccessUserAddress"].ToString(),
3697 string.Empty,
3698 store["AccessUserCity"].ToString(),
3699 store["AccessUserState"].ToString(),
3700 store["AccessUserZip"].ToString(),
3701 string.Empty,
3702 false,
3703 true,
3704 true,
3705 "<br/>"
3706 )
3707 <br/>
3708 @if (email.IsNotNullOrEmpty())
3709 {
3710 <strong>Email:</strong>
3711 <a href="mailto:@email" title="@store["AccessUserName"]">@email</a>
3712 <br/>
3713 }
3714 @if (phone.IsNotNullOrEmpty())
3715 {
3716 <strong>Ph:</strong>
3717 @phone<br/>
3718 }
3719 </p>
3720
3721 @if (website.IsNotNullOrEmpty())
3722 {
3723 <p><a href="@website" target="_blank" title="@store["AccessUserName"]">@website</a></p>
3724 }
3725
3726 <p><a href="@directionsLink" target="_blank" title="@Translate("Get Directions")">@Translate("Get Directions")</a></p>
3727
3728 <p class="distance"></p>
3729
3730 <div class="group-image-list">
3731 @if (user.Groups.Any())
3732 {
3733 foreach (var subGroup in user.Groups)
3734 {
3735 var buttonIcon = subGroup.CustomFieldValues.FirstOrDefault(x => x.CustomField.SystemName.Equals("AccessUser_ProductLineIcon", StringComparison.InvariantCultureIgnoreCase))?.Value.ToString();
3736
3737 if (!string.IsNullOrEmpty(buttonIcon))
3738 {
3739 <span class="group-image-container" title="@subGroup.Name">@ReadFile(groupIconPath + buttonIcon)</span>
3740 }
3741 }
3742 }
3743 </div>
3744 </div>
3745 </li>
3746 }
3747 </ol>
3748 }
3749 @Translate("Please contact your authorized dealer to purchase products.")
3750 </div>
3751 @SnippetStart("outScripts")
3752 <script type="text/javascript" src="//maps.googleapis.com/maps/api/js?v=3&libraries=geometry&key=@(generalSettings["GoogleMapsAPIKey"])"></script>
3753 @*START CUSTOM CODE*@
3754 var mapsJsFileSrc = $"{GetString("Template:DesignBaseUrl")}/Maps/javascripts/Maps.js";
3755 var mapsJsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath(mapsJsFileSrc));
3756
3757 <script type="text/javascript" src="@(mapsJsFileSrc)?@(mapsJsFileInfo.LastWriteTime.Ticks)"></script>
3758 @*END CUSTOM CODE*@
3759 @SnippetEnd("outScripts")
3760 }
3761
3762 @helper RenderStoresContentCustom()
3763 {
3764 DataRow[] stores = GetStoresFromDbCustom();
3765
3766 <h2 class="dealerPopupTitle hidden">@Translate("Find a Dealer")</h2>
3767 <div class="dynamicweb-map" id="Maps-85" data-list-position="hidden">
3768 <div class="col-xs-12" id="findStoreFilter">
3769 @RenderHeaderForZipcodeCustom()
3770 </div>
3771 @RenderStoresMapCustom(stores)
3772 <div id="storelistMaster" class="hidden"></div>
3773 </div>
3774 }
3775 }
3776 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
3777 @using Dynamicweb.Rendering
3778 @{
3779 @helper RenderStockStatusCustom(int productType, string stockStatusIcon, string stockStatusLabel)
3780 {
3781 // Only show if it's not a Service or Gift Card
3782 if (productType != 1 && productType != 3)
3783 {
3784 <div class="col-xs-12 noPadding stockStatus">
3785 @RenderIcon(stockStatusIcon, stockStatusLabel)
3786 </div>
3787 }
3788 }
3789 }
3790 @inherits RazorTemplateBase<RazorTemplateModel<Template>>
3791 @using Dynamicweb.Rendering
3792 @using Dynamicweb.Core
3793
3794 @helper RenderTrustSpotDisplay(string displayCode)
3795 {
3796 if (displayCode.IsNotNullOrEmpty())
3797 {
3798 @displayCode
3799 @SnippetStart("LastBodyCode")
3800 @Pageview.Area.Item["TrustSpotHeaderCode"]
3801 @SnippetEnd("LastBodyCode")
3802 }
3803 }
3804
3805 @helper RenderTrustSpotProductDisplay(string productSku)
3806 {
3807 if (productSku.IsNotNullOrEmpty())
3808 {
3809 @RenderTrustSpotDisplay((Pageview.Area.Item["TrustSpotProductPageDisplay"] ?? "").ToString().Replace("{productsku}", productSku))
3810 }
3811 }
3812 @{
3813 var productId = GetString("Ecom:Product.ID");
3814 // Redirect if there's primary page ID set
3815 if (Sanitize.Parameter("detail").IsNotNullOrEmpty() && GetInteger("Ecom:Product.PrimaryOrCurrentPageID") != Pageview.Page.ID)
3816 {
3817 var redirect = "Default.aspx?Id=" + GetString("Ecom:Product.PrimaryOrCurrentPageID") + "&ProductID=" + productId;
3818 if (Sanitize.Parameter("variantID").IsNotNullOrEmpty())
3819 {
3820 redirect += "&variantID=" + Sanitize.Parameter("variantID");
3821 }
3822 Dna.UrlServices.Helpers.Redirect(Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(redirect));
3823 }
3824 else
3825 {
3826 var page = Dynamicweb.Extensibility.ServiceLocator.Current.GetPageService().GetPage(GetPageIdByNavigationTag("GeneralSettings"));
3827 var generalSettings = Dynamicweb.Content.Items.Item.GetItemById(page.ItemType, page.ItemId);
3828 //Product
3829 var isVariantRequest = (System.Web.HttpContext.Current.Request["VariantID"] ?? "").ToString().IsNotNullOrEmpty() || GetInteger("Ecom:Product.VariantCount").Equals(0);
3830 var productType = GetInteger("Ecom:Product.Type");
3831 var currentVariantId = GetString("Ecom:Product.VariantID");
3832 var variantId = currentVariantId.IsNotNullOrEmpty() ? currentVariantId : GetString("Ecom:Product.DefaultVariantComboID");
3833 var productName = isVariantRequest ? GetString("Ecom:Product.Name") : GetString("Ecom:Product:Field.MasterProductName");
3834 var productNumber = GetString("Ecom:Product.Number");
3835 var productIntro = GetString("Ecom:Product.ShortDescription");
3836 var productDescription = GetString("Ecom:Product.LongDescription");
3837 var productDetails = GetString("Ecom:Product:Field.Details");
3838 var boatlifterMetaTitle = GetString("Ecom:Product:Field.BoatlifterMetaTitle").IsNotNullOrEmpty() ? GetString("Ecom:Product:Field.BoatlifterMetaTitle") : productName;
3839 var boatlifterMetaDescription = GetString("Ecom:Product:Field.BoatlifterMetaDescription");
3840 var productStock = 999999;
3841 var productDetailAjax = string.Concat("Default.aspx?ID=", GetPageIdByNavigationTag("ProductDetailAJAX").ToString() , "&GroupID=", GetString("Ecom:Group.ID") , "&ProductID=", GetString("Ecom:Product.ID"));
3842 if (isVariantRequest)
3843 {
3844 if (currentVariantId.IsNotNullOrEmpty())
3845 {
3846 productDetailAjax += "&VariantID=" + currentVariantId;
3847 }
3848 productDetailAjax += "&getproductinfo=true";
3849 }
3850 if (IsBoatlifterSite())
3851 {
3852 productDetails = GetString("Ecom:Product:Field.BoatlifterDetails");
3853 PageView.Current().Meta.Title = boatlifterMetaTitle;
3854 if (boatlifterMetaDescription.IsNotNullOrEmpty())
3855 {
3856 PageView.Current().Meta.AddTag("Description", boatlifterMetaDescription);
3857 }
3858 }
3859
3860 var productDetailRelatedAjax = string.Concat("Default.aspx?ID=", GetPageIdByNavigationTag("RelatedProductAJAX").ToString() , "&GroupID=", GetString("Ecom:Group.ID") , "&ProductID=", GetString("Ecom:Product.ID"));
3861 var productWarrantyId = GetString("Ecom:Product:Field.WarrantyId");
3862 var productImage = Dna.Hewitt.Images.GetHewittImagePath(this);
3863 var productAlternativeImage = Pageview.Area.Item["NoImage"] != null ? Pageview.Area.Item["NoImage"].ToString() : "/Files/Images/Hewitt/no-image-file.jpg";
3864
3865 <div id="product-container"
3866 data-amountrequired="@Translate("Amount is required")"
3867 data-pageId="@Pageview.Page.ID"
3868 data-productId="@productId"
3869 data-variantId="@variantId"
3870 data-errorCombination1="@Translate("Combination not available")">
3871 <div id="product-description" class="col-xs-12 noPadding">
3872 <div id="product-images" class="col-sm-6 col-xs-12 noPaddingLeft">
3873 <div id="product-lg-image" class="col-xs-12 noPaddingLeft">
3874 <figure class="text-center">
3875 @RenderImage(new ImageSettings
3876 {
3877 @*START CUSTOM CODE*@
3878 Source =$"/Admin/Public/GetImage.ashx?image={productImage}&altFmImage_path={productAlternativeImage}&width=600&height=415&Format=WebP&Crop=5&fillcanvas=1&Quality=100",
3879 @*END CUSTOM CODE*@
3880 AltText = productName,
3881 IncludeWrapper = false
3882 })
3883 <div class="hidden" id="videoContainer">
3884 <a id="playPause" href="#">
3885 @RenderIcon("fa-play")
3886 </a>
3887 <video id="video" width="100%" src="Video">
3888 Your browser does not support the video tag.
3889 </video>
3890 </div>
3891 </figure>
3892 </div>
3893 @RenderProductThumbnailsCustom(productImage, GetString("Ecom:Product:Field.ImageFileNamingPart.Value.Clean").IsNotNullOrEmpty() ? GetString("Ecom:Product:Field.ImageFileNamingPart.Value.Clean") : GetString("Ecom:Product.Number"), productName)
3894 </div>
3895 <div id="product-info-wrapper" class="col-sm-6 col-xs-12">
3896 <h1 class="product-title padding-bottom">@productName</h1>
3897 <div class="col-xs-12 noPadding">
3898 @if (productIntro.IsNotNullOrEmpty())
3899 {
3900 <div class="col-xs-12 noPadding productIntroduction">@productIntro</div>
3901 }
3902 @if (productNumber.IsNotNullOrEmpty() && isVariantRequest)
3903 {
3904 <span class="product-sku">@Translate("SKU"): @productNumber</span>
3905 }
3906 </div>
3907
3908 <div id="orderableContent">
3909 <div class="product-price col-sm-6 noPadding hiddenAtStart hidden"></div>
3910
3911 @if (GetDouble("Ecom:Product:Field.DisplayWeight") > 0)
3912 {
3913 <div class="displayWeight col-xs-12 noPadding">@Translate("Weight"): @GetString("Ecom:Product:Field.DisplayWeight") @Translate("lbs")</div>
3914 }
3915
3916 @RenderQuantityPricesCustom()
3917 <div class="order-now">
3918 @{
3919 var miniCartPageId = GetPageIdByNavigationTag("MiniCart");
3920 }
3921 <form name="addToCart" class="add-to-cart form-fields" action="@Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(miniCartPageId)" method="post" data-outofstock='@Translate("Out of stock")'>
3922 @{
3923 var loopVariantGroups = GetLoop("VariantGroups");
3924 @RenderVariantGroupsCustom(loopVariantGroups, isVariantRequest)
3925 }
3926 <div class="hiddenAtStart hidden">
3927 @RenderStockStatusCustom(productType, GetString("Ecom:Product:Stock.DeliveryUnit"), GetString("Ecom:Product:Stock.Text"))
3928 @RenderField(new FieldSettings
3929 {
3930 Type = FieldType.Textarea,
3931 Label = Translate("Comments"),
3932 SystemName = "EcomOrderlineFieldInput_Note",
3933 WrapperCssClass = "col-xs-12 noPadding",
3934 IncludeWrapper = true,
3935 Attributes = new Dictionary<string, string>
3936 {
3937 {"maxlength", "80"}
3938 }
3939 })
3940 @if (isVariantRequest)
3941 {
3942 <div class="col-xs-12 grayBox">
3943 <div class="highlight-content">
3944 @if (Dna.Hewitt.Helpers.IsUserBlockedInTheErp())
3945 {
3946 @RenderUserIsBlockedMessage()
3947 }
3948 else
3949 {
3950 @RenderQuantitySelector(loopVariantGroups.Any(), productStock, productType)
3951 @RenderAddToCart(productId, variantId, productStock)
3952 if (GetBoolean("Ecom:Product.CanBuyForPoints"))
3953 {
3954 @RenderBootstrapButton(new BootstrapButtonSettings
3955 {
3956 Label = Translate("Add with points"),
3957 Id = "addToCartPointsSubmit",
3958 IconCssClass = "fa-shopping-cart",
3959 Attributes = new Dictionary<string, string>
3960 {
3961 {"data-add", Translate("Add with points")},
3962 {"data-added", Translate("Added")}
3963 }
3964 })
3965 }
3966 }
3967 </div>
3968 </div>
3969 }
3970 </div>
3971 </form>
3972 </div>
3973 </div>
3974
3975 @if (isVariantRequest)
3976 {
3977 @RenderBootstrapButton(new BootstrapButtonSettings
3978 {
3979 Label = Translate("Find a Dealer"),
3980 CssClass = "btn-default topMargin20 findADealerPopup hidden"
3981 })
3982 }
3983
3984 <div class="col-xs-12 noPadding topMargin20">
3985 @if (isVariantRequest)
3986 {
3987 @RenderFavorites(GetBoolean("Ecom:Product.IsProductInFavoriteList"), productId, variantId, GetString("Ecom:Product.LanguageID"))
3988 }
3989 @RenderSocialMediaShare()
3990 </div>
3991
3992 @if (GetBoolean("Ecom:Product:Field.TrustSpotProductDisplays") && GetString("Ecom:Product.Number").IsNotNullOrEmpty())
3993 {
3994 <div class="col-xs-12 noPadding">
3995 @RenderTrustSpotProductDisplay(GetString("Ecom:Product.Number"))
3996 </div>
3997 }
3998
3999 </div>
4000 @* Tabs / Long description / Product custom field(example) / Downloads (items) *@
4001 @if (RenderSnippet("tabHeaders").ToString().IsNotNullOrEmpty() && (isVariantRequest || GetString("Ecom:Product.DefaultVariantComboID").IsNotNullOrEmpty()))
4002 {
4003 <div class="col-xs-12 noPadding">
4004 <div id="tabsContainer">
4005 <ul class="col-xs-12 noPadding">
4006 @RenderSnippet("tabHeaders")
4007 </ul>
4008 @if (GetString("Ecom:Product:Field.MeasurementID").IsNotNullOrEmpty())
4009 {
4010 @RenderTabContent("measuring_tab", Translate("Measuring Instructions"), GetProductMeasurement(GetString("Ecom:Product:Field.MeasurementID")), "measuring_tab active")
4011 }
4012
4013 @if (productDetails.IsNullOrEmpty() || productDescription.IsNullOrEmpty())
4014 {
4015 @RenderTabContent("description_tab", Translate("Description"), productDescription + productDetails)
4016 }
4017 else
4018 {
4019 @RenderTwoLineTabContent("description_tab", Translate("Description"), productDescription, productDetails)
4020 }
4021
4022 @InternalRenderTabHeader("#kitIncludes_tab", Translate("Kit Includes"), "kitIncludes_tab hidden")
4023 <div class="col-xs-12" id="kitIncludes_tab"></div>
4024
4025 @InternalRenderTabHeader("#partsBreakdown_tab", Translate("Parts Breakdown"), "partsBreakdown_tab hidden")
4026 <div class="col-xs-12 partsBreakdown_tab" id="partsBreakdown_tab"></div>
4027
4028 @if (productWarrantyId.IsNotNullOrEmpty())
4029 {
4030 @RenderTabContent("warranty_tab", Translate("Warranty"), GetProductWarranty(productWarrantyId), "warranty_tab")
4031 }
4032
4033 @RenderDownloadsTab()
4034 @RenderDownloadItemsTabCustom()
4035 @RenderVideosTab()
4036 @if (Dna.Hewitt.Helpers.IsUserB2B())
4037 {
4038 @InternalRenderTabHeader("#specSheets_tab", Translate("Spec Sheets"), "specSheets_tab hidden")
4039 <div class="col-xs-12 specSheets_tab" id="specSheets_tab"></div>
4040 }
4041 @InternalRenderTabHeader("#productreviews_tab", Translate("Reviews"), "productreviews_tab")
4042 <div class="col-xs-12 productreviews_tab" id="productreviews_tab">
4043 <div class="trustspot trustspot-main-widget" data-product-sku="@GetString("Ecom:Product.Number")" data-name="@productName"></div>
4044 </div>
4045 </div>
4046 </div>
4047 }
4048 </div>
4049 </div>
4050 <script type="text/javascript" src="//maps.googleapis.com/maps/api/js?v=3&libraries=geometry&key=@(generalSettings["GoogleMapsAPIKey"])"></script>
4051 @*START CUSTOM CODE*@
4052 var mapsJsFileSrc = $"{GetString("Template:DesignBaseUrl")}/Maps/javascripts/Maps.js";
4053 var mapsJsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath(mapsJsFileSrc));
4054
4055 <script type="text/javascript" src="@(mapsJsFileSrc)?@(mapsJsFileInfo.LastWriteTime.Ticks)"></script>
4056 @*END CUSTOM CODE*@
4057 @RenderOpenGraphMeta("product", productImage, productName, productIntro.IsNotNullOrEmpty() ? productIntro : productDescription)
4058 @SnippetStart("jsOnLoad")
4059 @:onLoadProductDetailInit({variants: "@(productDetailAjax)", related: "@(productDetailRelatedAjax)", settings: {productspernumber: "@Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(GetPageIdByNavigationTag("ProductsPerNumber"))", specSheetsPage: "@Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(GetPageIdByNavigationTag("specSheets"))", searchParameter: "@Dna.Hewitt.Constants.FilesRepository.SearchParameter", weightText: "@(string.Format("{0}: XXX {1}", Translate("Weight"), Translate("lbs")))"}});
4060 @SnippetEnd("jsOnLoad")
4061 }
4062 }
4063 @*
4064 Simulate request of tags to trigger DW's template engine render the property data
4065 @GetString("Ecom:Product.ImageSmall.Clean")
4066 @GetString("Ecom:Product.ImageMedium.Clean")
4067 @GetString("Ecom:Product.ImageLarge.Clean")
4068 @GetString("Ecom:Product:Field.ImageFileNamingPart.Value.Clean")
4069 *@