Error executing template "Designs/Hewitt/eCom/Product/Product.cshtml"
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
   at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Enumerator.MoveNext()
   at Dynamicweb.Modules.Searching.Rules.Parser.UnescapeStrings(String s)
   at Dynamicweb.Modules.Searching.Rules.Parser.ParseSimpleExpression(String expression)
   at Dynamicweb.Modules.Searching.Rules.Parser.Parse(String input)
   at Dynamicweb.ItemPublisher.FilterHelper.ToXml(String filter)
   at Dynamicweb.ItemPublisher.Frontend.GetContentBySettings(String settings)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Dynamicweb.Extensibility.AddIns.AddInManager.InvokeFunction(Object instance, String functionName, Object[] arguments)
   at Dynamicweb.Rendering.TemplateBase`1.RenderItemList(Object settings)
   at CompiledRazorTemplates.Dynamic.RazorEngine_8ba0182e86584c9581da6bbb0c540b61.<RenderDownloadsTab>b__105_0(TextWriter __razor_helper_writer) in f:\Domains\Sites\hewittrad.com\Files\Templates\Designs\Hewitt\eCom\Product\Product.cshtml:line 2595
   at CompiledRazorTemplates.Dynamic.RazorEngine_8ba0182e86584c9581da6bbb0c540b61.Execute() in f:\Domains\Sites\hewittrad.com\Files\Templates\Designs\Hewitt\eCom\Product\Product.cshtml:line 4033
   at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
   at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()

1 @inherits 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", "&#x1f4c5;")); 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", "&#xf073;"} 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 = "&nbsp;"; 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">&nbsp;</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 = "&nbsp;"; 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>&nbsp;</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, "&amp;variantID=", productVariantId, "&amp;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 @:&nbsp; 2149 <a title="@socialName" target="_blank" href="@socialLink">@socialName</a> 2150 @:&nbsp; 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 + "&amp;CC{{favoriteAction}}MyLists=" + productId + "&amp;CC{{favoriteAction}}ListVariantID=" + variantId + "&amp;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">&nbsp;</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&amp;libraries=geometry&amp;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&amp;libraries=geometry&amp;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&amp;libraries=geometry&amp;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 *@