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