Exception in template (Designs\OutletCamping\eCom/Productlist/ProductListFacets.cshtml): System.NullReferenceException: Object reference not set to an instance of an object.
at CompiledRazorTemplates.Dynamic.dbdcbeffb.Execute()
at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context) in c:\Users\abbottm\Documents\GitHub\RazorEngine\src\Core\RazorEngine.Core\Templating\TemplateBase.cs:line 126
at RazorEngine.Templating.TemplateService.Run(ITemplate template, DynamicViewBag viewBag) in c:\Users\abbottm\Documents\GitHub\RazorEngine\src\Core\RazorEngine.Core\Templating\TemplateService.cs:line 608
at RazorEngine.Templating.TemplateService.Parse(String razorTemplate, Object model, DynamicViewBag viewBag, String cacheName) in c:\Users\abbottm\Documents\GitHub\RazorEngine\src\Core\RazorEngine.Core\Templating\TemplateService.cs:line 439
at RazorEngine.Razor.Parse[T](String razorTemplate, T model, DynamicViewBag viewBag, String cacheName) in c:\Users\abbottm\Documents\GitHub\RazorEngine\src\Core\RazorEngine.Core\Razor.cs:line 290
at Dynamicweb.Rendering.Template.RenderRazorTemplate()
@using System
@using System.Collections.Generic
@using System.Globalization
@using System.Linq
@using System.Web
@using Dynamicweb.Data;
@using Dynamicweb.Extensibility
@using Dynamicweb.Frontend
@using Dynamicweb.Ecommerce.Products
@using Dynamicweb.Indexing.Querying
@using OaseOutdoors.Components.Shared.Modules.Ecom.ModelBuilders
@using OaseOutdoors.Components.Shared.Modules.Ecom.Models
@using OaseOutdoors.Services.EcomUrlService.Initialization
@using OaseOutdoors.Services.UrlParserService.Initialization
@using OaseOutdoors.Services.FacetService.Models
@using OaseOutdoors.Services.GroupService.Initialization
@using OaseOutdoors.Services.ImageService.Enums
@using OaseOutdoors.Services.ImageService.Initialization
@using OaseOutdoors.Services.ProductResourceService.Enums
@using OaseOutdoors.Services.ProductResourceService.Initialization
@using OaseOutdoors.Services.ProductService.Initialization
@using OaseOutdoors.Services.StaticResourceService.Initialization
@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
@{
var staticResourceService = ServiceLocator.Current.GetStaticResourceService();
var area = PageView.Current().Area;
var areas = Dynamicweb.Services.Areas.GetAreas().Where(x => x.Active && x.Item["ShopPublished"] != null && (bool)x.Item["ShopPublished"] && x.Name.ToLower().Contains(area.Name.Split(':')[0].Trim().ToLower())).ToList();
string groupId = GetString("Ecom:Group.ID");
var group = Group.GetGroupById(groupId);
var productViewModelService = new ProductViewModelBuilder();
var groupViewModelService = new GroupViewModelBuilder();
if (group.ShopId != Pageview.Area.EcomShopId)
{
var groupContext = HttpContext.Current;
groupContext.Response.RedirectPermanent(new Uri(groupContext.Request.Url.Scheme + "://" + groupContext.Request.Url.Host + groupContext.Request.RawUrl).GetLeftPart(UriPartial.Path) + "-404", true);
}
var groupService = ServiceLocator.Current.GetGroupService();
var groupViewModel = groupViewModelService.GetViewModel(group);
var beginSection = "<div class=\"container\"><section class=\"product-container\">";
var endSection = "</section></div>";
var urlService = ServiceLocator.Current.GetEcomUrlService();
var urlParserService = ServiceLocator.Current.GetUrlParserService();
var valutaSelector = HttpContext.Current.Request.Cookies["currencySelector"];
GroupCollection subGroups = null;
if (group != null && group.HasChildGroups && group.Subgroups.Count >= 1)
{
subGroups = group.Subgroups;
}
else if (group != null && group.ParentGroups.Count > 0)
{
subGroups = group.ParentGroups.FirstOrDefault().Subgroups;
}
int breadCrumbTotal = groupViewModel.Breadcrumb.Count;
int breadCrumbIndex = 1;
var queryService = ServiceLocator.Current.GetInstance<IQueryService>();
var query = queryService.LoadQuery("Products", "ProductsSortAndFilter" + ".query");
var productService = ServiceLocator.Current.GetProductService();
var parameters = new Dictionary<string, object> { { "groupId", groupId } };
////Price
var heighestPriceProduct = productService.GetHighestOrLowest(query, parameters, Dynamicweb.Indexing.Querying.Sorting.SortDirection.Descending, "Price");
double heighestPrice = 0.0;
var currencySymbol = "";
if (heighestPriceProduct != null)
{
heighestPrice = Math.Ceiling(heighestPriceProduct.Price.PriceWithVAT);
currencySymbol = heighestPriceProduct.Price.Currency.Symbol;
}
var lowestPriceProduct = productService.GetHighestOrLowest(query, parameters, Dynamicweb.Indexing.Querying.Sorting.SortDirection.Ascending, "Price");
double lowestPrice = 0.0;
if (lowestPriceProduct != null)
{
lowestPrice = Math.Floor(lowestPriceProduct.Price.PriceWithVAT);
}
var currentPriceQueryString = (!string.IsNullOrWhiteSpace(HttpContext.Current.Request.QueryString.Get("pricevat"))) ? HttpContext.Current.Request.QueryString.Get("pricevat") : HttpContext.Current.Request.QueryString.Get("pricevateur");
string[] currentPriceArray = { };
if (!string.IsNullOrWhiteSpace(currentPriceQueryString))
{
currentPriceArray = currentPriceQueryString.Split(',');
}
var currentPriceLowValue = lowestPrice;
var currentPriceHighValue = heighestPrice;
if (currentPriceArray.Length == 2)
{
var currentPriceLowQuery = currentPriceArray.FirstOrDefault();
if (!string.IsNullOrWhiteSpace(currentPriceLowQuery))
{
currentPriceLowValue = Convert.ToInt32(currentPriceLowQuery);
}
var currentPriceHighQuery = currentPriceArray.LastOrDefault();
if (!string.IsNullOrWhiteSpace(currentPriceHighQuery))
{
currentPriceHighValue = Convert.ToInt32(currentPriceHighQuery);
}
}
////end price
//Weight
var heighestWeightProduct = productService.GetHighestOrLowest(query, parameters, Dynamicweb.Indexing.Querying.Sorting.SortDirection.Descending, "WeightNotAnalyzed");
double heighestWeight = 0.0;
if (heighestWeightProduct != null)
{
heighestWeight = Math.Ceiling(heighestWeightProduct.Weight);
}
var lowestWeightProduct = productService.GetHighestOrLowest(query, parameters, Dynamicweb.Indexing.Querying.Sorting.SortDirection.Ascending, "WeightNotAnalyzed");
double lowestWeight = 0.0;
if (lowestWeightProduct != null)
{
lowestWeight = Math.Floor(lowestWeightProduct.Weight);
}
var currentWeightQueryString = HttpContext.Current.Request.QueryString.Get("weight");
string[] currentWeightArray = { };
if (!string.IsNullOrWhiteSpace(currentWeightQueryString))
{
currentWeightArray = currentWeightQueryString.Split(',');
}
var currentWeightLowValue = lowestWeight;
var currentWeightHighValue = heighestWeight;
if (currentWeightArray.Length == 2)
{
var currentWeightLowQuery = currentWeightArray.FirstOrDefault();
if (!string.IsNullOrWhiteSpace(currentWeightLowQuery))
{
currentWeightLowValue = Convert.ToInt32(currentWeightLowQuery);
}
var currentWeightHighQuery = currentWeightArray.LastOrDefault();
if (!string.IsNullOrWhiteSpace(currentWeightHighQuery))
{
currentWeightHighValue = Convert.ToInt32(currentWeightHighQuery);
}
}
}
@SnippetStart("canonical")
<link rel="canonical" href="@groupViewModel.Canonical" />
@foreach (var hrefLang in groupViewModel.HrefLangs)
{
<link rel="alternate" hreflang="@hrefLang.HrefLang" href="@hrefLang.Href" />
}
@SnippetEnd("canonical")
@SnippetStart("languageSelector")
<ul>
@foreach (var languageArea in areas)
{
var hrefLang = groupViewModel.HrefLangs.FirstOrDefault(x => x.HrefAreaId == languageArea.ID);
if (hrefLang == null || hrefLang.Href.ToLower().Contains("page-not-found"))
{
hrefLang = new HrefLangViewModel();
hrefLang.HrefName = languageArea.Item["ShopLanguageName"].ToString() ?? string.Empty;
hrefLang.HrefLang = languageArea.CultureInfo.Name;
hrefLang.Href = "/Default.aspx?areaid=" + languageArea.ID;
hrefLang.HrefAreaId = languageArea.ID;
}
if (hrefLang != null && hrefLang.HrefLang != "x-default")
{
<li class="country-picker__item @(hrefLang.HrefAreaId == Pageview.AreaID ? "country-picker__item--current" : string.Empty)">
<a href="@hrefLang.Href">
<svg aria-hidden="true">
<use xlink:href="@staticResourceService.AddTimeStamp("/static/dist/svg/_bundle.svg")#outletcamping-arrow-right"></use>
</svg>
<span>@hrefLang.HrefName</span>
</a>
</li>
}
}
</ul>
@SnippetEnd("languageSelector")
@if (groupViewModel.Hero != null)
{
@RenderParagraphContent(groupViewModel.Hero.ID)
}
@helper SortingMarkup(GroupViewModel groupViewModel, String triggerId, Boolean initModule = true)
{
var rawUrl = Dynamicweb.Context.Current.Request.Url;
var uri = new Uri(rawUrl.ToString());
// this gets all the query string key value pairs as a collection
var newQueryString = HttpUtility.ParseQueryString(uri.Query);
// this removes the key if exists
newQueryString.Remove("sortby");
newQueryString.Remove("sortorder");
var baseUrl = uri.GetLeftPart(UriPartial.Path);
baseUrl = newQueryString.Count > 0 ? String.Format("{0}?{1}", baseUrl, newQueryString) : baseUrl;
baseUrl = baseUrl.Contains("?") ? baseUrl + "&" : baseUrl + "?";
<div class="sorting" @(initModule ? "data-module=\"sorting\"" : string.Empty)>
<input id="product-list-sorting-@triggerId" type="checkbox" class="trigger">
<label for="product-list-sorting-@triggerId" class="sorting__button btn">
<span class="btn__icon">
<svg role="img"><use xlink:href="@groupViewModel.StaticResourceService.AddTimeStamp("/static/dist/svg/_bundle.svg")#sorting"></use></svg>
</span>
<span class="btn__text">
@Translate("Sorting", "Sorting"):
@if (HttpContext.Current.Request.QueryString.Get("sortby") == "Price")
{
@Translate("Price", "Price")
}
else if (HttpContext.Current.Request.QueryString.Get("sortby") == "ProductTitle")
{
@Translate("Alphabetical", "Alphabetical")
}
else
{
@Translate("Standard", "Standard")
}
</span>
</label>
<div class="sorting__options">
<ul>
<li>
<a href="@(baseUrl)">@Translate("Standard", "Standard")</a>
</li>
<li>
<a href="@(baseUrl)sortby=Price&sortorder=asc">@Translate("Price", "Price")</a>
</li>
<li>
<a href="@(baseUrl)sortby=ProductTitle&sortorder=asc">@Translate("Alphabetical", "Alphabetical")</a>
</li>
</ul>
</div>
</div>
}
<section class="content content--breadcrumb container-ribbon">
<div class="container">
<ol class="breadcrumb" itemscope itemtype="http://schema.org/BreadcrumbList">
@foreach (var item in groupViewModel.Breadcrumb)
{
if (item == groupViewModel.Breadcrumb.LastOrDefault())
{
<li class="breadcrumb__item @(item == groupViewModel.Breadcrumb.LastOrDefault() ? "breadcrumb__item--current" : "")" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">
<meta itemprop="item" href="@item.Link">
<a>
<span itemprop="name">
@if (breadCrumbIndex == breadCrumbTotal - 1)
{
@* The second to last breadcrumb item is the only one visible on mobile devices and thus the only one with this SVG *@
<svg aria-hidden="true"><use xlink:href="@groupViewModel.StaticResourceService.AddTimeStamp("/static/dist/svg/_bundle.svg")#arrow-left"></use></svg>
}
@item.LinkTitle
</span>
</a>
<meta itemprop="position" content="@breadCrumbIndex">
</li>
}
else
{
<li class="breadcrumb__item @(item == groupViewModel.Breadcrumb.LastOrDefault() ? "breadcrumb__item--current" : "")" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">
<a itemprop="item" href="@item.Link">
<span itemprop="name">
@if (breadCrumbIndex == breadCrumbTotal - 1)
{
@* The second to last breadcrumb item is the only one visible on mobile devices and thus the only one with this SVG *@
<svg aria-hidden="true"><use xlink:href="@groupViewModel.StaticResourceService.AddTimeStamp("/static/dist/svg/_bundle.svg")#arrow-left"></use></svg>
}
@item.LinkTitle
</span>
</a>
<meta itemprop="position" content="@breadCrumbIndex">
</li>
}
breadCrumbIndex++;
}
</ol>
</div>
</section>
@if (subGroups != null)
{
<section class="content content--subnavigation container-ribbon">
<div class="container">
<nav class="subnavigation">
<ul>
@foreach (var subGroup in subGroups)
{
var productsCount = groupService.GetProductsCount(subGroup);
<li class="subnavigation__item @(subGroup.Id == groupId ? "subnavigation__item--active" : "")">
<a href="@urlService.GetUrl(subGroup.IdUrlEncoded)">
@subGroup.Name @(productsCount == 0 ? "" : "(" + productsCount + ")")
</a>
</li>
}
</ul>
</nav>
</div>
</section>
}
@if (group != null && group.HasProducts())
{
int count = 0;
int ribbonIndex = 0;
<section class="content content--product-list-title container-ribbon">
<div class="container">
<button type="button" class="filters-toggle">
<div>
<svg role="img"><use xlink:href="@groupViewModel.StaticResourceService.AddTimeStamp("/static/dist/svg/_bundle.svg")#filters"></use></svg>
</div>
<div class="header__expand-menu-title" style="margin-left:0px;">FILTER</div>
</button>
@SortingMarkup(groupViewModel, "1")
<div>
@if (groupViewModel.Hero != null)
{
<span class="h-1">@group.Name</span>
}
else
{
<h1><span class="h-1">@group.Name</span></h1>
}
</div>
</div>
</section>
foreach (var facetGroup in GetLoop("FacetGroups"))
{
if (subGroups != null)
{
<section class="content content--product-list-subgroups">
<section class="filter__groups">
<div class="container">
<nav>
<ul style="background-color: #deeeed;margin: 5px;">
@foreach (var subGroup in subGroups)
{
var productsCount = groupService.GetProductsCount(subGroup);
<li class="filter__groups-item @(subGroup.Id == groupId ? "subnavigation__item--active" : "")">
<a href="@urlService.GetUrl(subGroup.IdUrlEncoded)">
@subGroup.Name @(productsCount == 0 ? "" : "(" + productsCount + ")")
</a>
</li>
}
</ul>
</nav>
</div>
</section>
</section>
}
<section class="filter filter--hidden-on-mobile content content--product-list-filters container-ribbon"
data-see-more="@Translate("SeeMore", "See more")"
data-total-page-count="@GetString("Ecom:ProductList.TotalPages")"
data-total-number="@GetString("Ecom:ProductList.PageProdCnt")"
data-group-id="@group.Id"
data-module="filter">
<form>
<div class="container">
<div class="filter__container">
<div class="filter__icon-container">
<span class="filter__icon">
<svg role="img"><use xlink:href="@groupViewModel.StaticResourceService.AddTimeStamp("/static/dist/svg/_bundle.svg")#filters"></use></svg>
</span>
</div>
<div class="filter__facets">
@*Weight*@
@if (lowestWeight < heighestWeight)
{
<div class="filter__facets-container filter__facets-container--large" data-facet-name="@Translate("weight", "Weight")" data-facet-queryname="weight">
<div class="filter__facet">
<div class="filter__facet-head">
<span class="btn">
<span class="btn__icon">
<svg role="img">
<use xlink:href="@groupViewModel.StaticResourceService.AddTimeStamp("/static/dist/svg/_bundle.svg")#outletcamping-arrow-right"></use>
</svg>
</span>
<span class="btn__text">@Translate("weight", "Weight")</span>
</span>
</div>
<div class="filter__facet-body filter__facet-body--slider">
<div class="filter__range" id="range-filter-weight"
data-range-current-min="@currentWeightLowValue"
data-range-current-max="@currentWeightHighValue"
data-range-min="@lowestWeight"
data-range-max="@heighestWeight"
data-range-unit="kg"
data-range-name="weight"></div>
<div class="range-filter__container">
<div class="range-filter-weight-min"></div>
<div class="range-filter-weight-max"></div>
</div>
<input id="weight-min" hidden name="weight" type="text" value="@currentWeightLowValue" />
<input id="weight-max" hidden name="weight" type="text" value="@currentWeightHighValue" />
</div>
</div>
</div>
}
@*Price*@
@if (lowestPrice < heighestPrice && (valutaSelector == null || Pageview.AreaID != 1))
{
<div class="filter__facets-container filter__facets-container--large" data-facet-name="@Translate("price", "Price")" data-facet-queryname="pricevat">
<div class="filter__facet">
<div class="filter__facet-head">
<span class="btn">
<span class="btn__icon">
<svg role="img">
<use xlink:href="@groupViewModel.StaticResourceService.AddTimeStamp("/static/dist/svg/_bundle.svg")#outletcamping-arrow-right"></use>
</svg>
</span>
<span class="btn__text">@Translate("price", "Price")</span>
</span>
</div>
<div class="filter__facet-body filter__facet-body--slider">
<div class="filter__range" id="range-filter-pricevat"
data-range-current-min="@currentPriceLowValue"
data-range-current-max="@currentPriceHighValue"
data-range-min="@lowestPrice"
data-range-max="@heighestPrice"
data-range-unit="@currencySymbol"
data-range-name="pricevat"></div>
<div class="range-filter__container">
<div class="range-filter-pricevat-min"></div>
<div class="range-filter-pricevat-max"></div>
</div>
<input id="pricevat-min" hidden name="pricevat" type="text" value="@currentPriceLowValue" />
<input id="pricevat-max" hidden name="pricevat" type="text" value="@currentPriceHighValue" />
</div>
</div>
</div>
}
@if (lowestPrice < heighestPrice && (valutaSelector != null && Pageview.AreaID == 1))
{
<div class="filter__facets-container filter__facets-container--large" data-facet-name="@Translate("price", "Price")" data-facet-queryname="pricevateur">
<div class="filter__facet">
<div class="filter__facet-head">
<span class="btn">
<span class="btn__icon">
<svg role="img">
<use xlink:href="@groupViewModel.StaticResourceService.AddTimeStamp("/static/dist/svg/_bundle.svg")#outletcamping-arrow-right"></use>
</svg>
</span>
<span class="btn__text">@Translate("price", "Price")</span>
</span>
</div>
<div class="filter__facet-body filter__facet-body--slider">
<div class="filter__range" id="range-filter-pricevateur"
data-range-current-min="@currentPriceLowValue"
data-range-current-max="@currentPriceHighValue"
data-range-min="@lowestPrice"
data-range-max="@heighestPrice"
data-range-unit="@currencySymbol"
data-range-name="pricevateur"></div>
<div class="range-filter__container">
<div class="range-filter-pricevateur-min"></div>
<div class="range-filter-pricevateur-max"></div>
</div>
<input id="pricevateur-min" hidden name="pricevateur" type="text" value="@currentPriceLowValue" />
<input id="pricevateur-max" hidden name="pricevateur" type="text" value="@currentPriceHighValue" />
</div>
</div>
</div>
}
@*end price*@
@foreach (var facet in facetGroup.GetLoop("Facets"))
{
var renderType = facet.GetString("Facet.RenderType");
var optionsCount = facet.GetInteger("Facet.OptionWithResultCount");
if (optionsCount < 1 || renderType == "Range" && optionsCount < 2)
{
continue;
}
var facetMinValue = 0;
var facetMaxValue = 0;
List<int> facetValues = new List<int>();
var facetOptions = facet.GetLoop("FacetOptions");
if (renderType == "Range")
{
foreach (var facetOption in facetOptions)
{
var facetValue = facetOption.GetString("FacetOption.Value").Trim();
if (isStringInt(facetValue) && int.Parse(facetValue) > 0)
{
facetValues.Add(int.Parse(facetValue));
}
}
facetMinValue = facetValues.Min();
facetMaxValue = facetValues.Max();
}
string facetClass = "filter__facets-container";
if (facet.GetString("Facet.QueryParameter") == "color")
{
facetClass = "filter__facets-container filter__facets-container--large";
}
var id = 0;
var faceType = (renderType == "Range") ? "filter__facet-body--slider" : string.Empty;
var queryParam = facet.GetString("Facet.QueryParameter");
if(renderType == "Range" && facetMinValue < facetMaxValue || renderType != "Range") {
<div class="@facetClass" data-facet-name="@facet.GetString("Facet.Name")" data-facet-queryname="@facet.GetString("Facet.QueryParameter")">
<div class="filter__facet">
<div class="filter__facet-head">
<span class="btn">
<span class="btn__icon">
<svg role="img">
<use xlink:href="@groupViewModel.StaticResourceService.AddTimeStamp("/static/dist/svg/_bundle.svg")#outletcamping-arrow-right"></use>
</svg>
</span>
<span class="btn__text">@Translate(facet.GetString("Facet.Name"), facet.GetString("Facet.Name"))</span>
</span>
</div>
<div class="filter__facet-body @faceType">
@switch (renderType)
{
case "Checkboxes":
foreach (var facetOption in facetOptions)
{
<div class="filter__facet-seperator">
<input type="checkbox" @(facetOption.GetBoolean("FacetOption.Selected") ? "checked" : "") name="@facet.GetString("Facet.QueryParameter")" value="@facetOption.GetString("FacetOption.Value")" id="@facet.GetString("Facet.QueryParameter")@id" />
<label for="@facet.GetString("Facet.QueryParameter")@id">
@facetOption.GetString("FacetOption.Label").Replace("xxx", " ")
@if (facet.GetString("Facet.QueryParameter") == "width" || facet.GetString("Facet.QueryParameter") == "height")
{
<text>cm</text>
}
</label>
</div>
id++;
}
break;
case "Range":
if (facetValues.Count > 0)
{
string[] facetSelectedValues = { facetMinValue.ToString(), facetMaxValue.ToString() };
if (HttpContext.Current.Request.QueryString.Get(queryParam) != null)
{
facetSelectedValues = HttpContext.Current.Request.QueryString.Get(queryParam).Split(',');
}
var facetCurrentMinValue = facetSelectedValues[0];
var facetCurrentMaxValue = facetSelectedValues[1];
<div class="filter__range" id="range-filter-@queryParam"
data-range-current-min="@facetCurrentMinValue"
data-range-current-max="@facetCurrentMaxValue"
data-range-min="@facetMinValue"
data-range-max="@facetMaxValue"
data-range-unit="@Translate(queryParam + "-unit", queryParam + "-unit")"
data-range-name="@queryParam">
</div>
<div class="range-filter__container">
<div class="range-filter-@queryParam-min"></div>
<div class="range-filter-@queryParam-max"></div>
</div>
<input id="@queryParam-min" hidden name="@queryParam" type="text" value="@facetCurrentMinValue" />
<input id="@queryParam-max" hidden name="@queryParam" type="text" value="@facetCurrentMaxValue" />
}
break;
}
</div>
</div>
</div>
}
}
</div>
<div class="filter__filter-container">
<button type="button" class="filter__list-item filter__filter-reset filter__filter-reset--hidden">
<span>@Translate("FilterResetAll", "Reset all")</span>
</button>
<button class="btn btn--filled">
<span class="btn__text">@Translate("Filter", "Filter")</span>
</button>
</div>
@SortingMarkup(groupViewModel, "2", false)
</div>
<div class="filter__list-container hidden">
<div class="filter__list"></div>
<button type="button" class="filter__list-item filter__filter-reset">
<span>
<svg role="img">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/static/dist/svg/_bundle.svg#close"></use>
</svg>
</span>
<span>@Translate("FilterResetAll", "Reset all")</span>
</button>
</div>
</div>
@if (!String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("sortby")))
{
<input name="sortby" type="hidden" value="@HttpContext.Current.Request.QueryString.Get("sortby")">
}
@if (!String.IsNullOrEmpty(HttpContext.Current.Request.QueryString.Get("sortorder")))
{
<input name="sortorder" type="hidden" value="@HttpContext.Current.Request.QueryString.Get("sortorder")">
}
</form>
</section>
}
<section class="content content--body">
<div class="product-item-wrapper container-ribbon">
<div class="container">
<section class="product-container">
@foreach (var p in GetLoop("Products"))
{
if (groupViewModel.HeroProduct != null && p.GetString("Ecom:Product.ID") == groupViewModel.HeroProduct.Id)
{
// Skip if this is the chosen hero product
continue;
}
if (groupViewModel.IsFiltered == false && count % 6 == 0 && count > 0)
{
if (count == 6 && groupViewModel.HeroProduct != null)
{
//Show hero
@RenderHeroProduct(groupViewModel.HeroProduct, groupViewModel, true)
}
else if (count == 6 && groupViewModel.FeaturedRibbonIds.Count > ribbonIndex && ribbonIndex != groupViewModel.FeaturedRibbonIds.Count - 1)
{
@endSection
//Show embedded content
@RenderParagraphContent(groupViewModel.FeaturedRibbonIds[ribbonIndex])
ribbonIndex++;
@beginSection
}
else if (count > 0 && groupViewModel.FeaturedRibbonIds.Count > ribbonIndex && ribbonIndex != groupViewModel.FeaturedRibbonIds.Count - 1)
{
@endSection
//Show embedded content
@RenderParagraphContent(groupViewModel.FeaturedRibbonIds[ribbonIndex])
ribbonIndex++;
@beginSection
}
}
count++;
@RenderProduct(p, groupViewModel, false)
}
@if (groupViewModel.IsFiltered == false && groupViewModel.FeaturedRibbonIds != null && groupViewModel.FeaturedRibbonIds.Count > ribbonIndex)
{
@endSection
//Render any remaining ribbons on product page
for (int i = ribbonIndex; i < groupViewModel.FeaturedRibbonIds.Count; i++)
{
if (i != groupViewModel.FeaturedRibbonIds.Count - 1)
{
@RenderParagraphContent(groupViewModel.FeaturedRibbonIds[i])
}
}
@beginSection
}
@if (groupViewModel.FeaturedRibbonIds.Count > 0)
{
@RenderParagraphContent(groupViewModel.FeaturedRibbonIds[groupViewModel.FeaturedRibbonIds.Count - 1])
}
</section>
<div class="search-results__button">
<span class="btn">
<span class="btn__text">@Translate("LoadMore", "Load More")</span>
</span>
</div>
</div>
</div>
@if (groupViewModel.SEO != null)
{
@RenderParagraphContent(groupViewModel.SEO.ID)
}
</section>
}
@helper RenderProduct(LoopItem product, GroupViewModel groupViewModel, bool isHero)
{
var productClass = isHero ? "product-item--hero" : "product-item--flex";
<article itemscope itemtype="http://schema.org/Product" class="product-item @productClass">
<link itemprop="brand" content="@product.GetString("Ecom:Product:Field.BrandName")" />
<link itemprop="description" content="@product.GetString("Ecom:Product.LongDescription")" />
<link itemprop="sku" content="@product.GetString("Ecom:Product.Number")" />
<a itemprop="url" href="@groupViewModel.UrlService.GetUrl(groupViewModel.Id, product.GetString("Ecom:Product.ID"))">
<div class="product-item__header">
@{
var imageService = ServiceLocator.Current.GetImageService();
var productResourceService = ServiceLocator.Current.GetProductResourceService();
var imagePath = productResourceService.Get(product.GetString("Ecom:Product:Field.Image001"), FileFormat.Jpeg);
var img = imageService.Begin(imagePath);
var imgSrc = img.SetWidth(800).SetHeight(800).SetCrop(CropType.KeepAspectRatio).SetCompression(80).GetCrop();
var imgClass = "";
if (Pageview.Device == 0 && product.GetString("Ecom:Product:Field.Image062") != "")
{
var imageHoverPath = productResourceService.Get(product.GetString("Ecom:Product:Field.Image062"), FileFormat.Jpeg);
var imgHover = imageService.Begin(imageHoverPath);
var imgHoverSrc = imgHover.SetWidth(800).SetHeight(800).SetCrop(CropType.KeepAspectRatio).SetCompression(80).GetCrop();
imgClass = "orig";
<figure class="lazy hover" data-src-sm="@imgHoverSrc" data-alt="@product.GetString("Ecom:Product.Name")">
<noscript><img src="@imgHoverSrc" itemprop="image" content="@imgHoverSrc" alt="Outwell @product.GetString("Ecom:Product.Name")"></noscript>
</figure>
}
}
<figure class="lazy" data-src-sm="@imgSrc" data-alt="@product.GetString("Ecom:Product.Name")">
<noscript><img src="@imgSrc" itemprop="image" content="@imgSrc" alt="@product.GetString("Ecom:Product.Name")"></noscript>
</figure>
@if (!string.IsNullOrEmpty(product.GetString("Ecom:Product:Field.OutletcampingSplash")) && !string.IsNullOrEmpty(product.GetString("Ecom:Product:Field.OutletcampingSplashColor")))
{
var splashTexts = product.GetString("Ecom:Product:Field.OutletcampingSplash").Split(' ');
<div class="product-item__splash" style="z-index:100;background: @product.GetString("Ecom:Product:Field.OutletcampingSplashColor");">
<div class="product-item__splash-text">
<p>
@for (var i = 0; i <= splashTexts.Length - 1; i++)
{
if (i == 1)
{
<span class="product-item__splash-text--bold"> @splashTexts[i]</span>
}
else
{
@splashTexts[i]
}
}
</p>
</div>
</div>
}
</div>
<div class="product-item__body">
@{
var periodEndDateSql = Database.ExecuteScalar(CommandBuilder.Create("SELECT p.PeriodEndDate FROM EcomProducts AS ep INNER JOIN EcomPeriods AS p ON ep.ProductPeriodId = p.PeriodId WHERE ep.ProductId = {0} AND ep.ProductLanguageId = {1}", product.GetString("Ecom:Product.ID"), product.GetString("Ecom:Product.LanguageID")));
var periodEndDate = (periodEndDateSql != null) ? (DateTime)periodEndDateSql : DateTime.MinValue;
if (periodEndDate >= DateTime.Now && periodEndDate <= DateTime.Now.AddDays(14))
{
<div data-module="countdown">
<div class="product-item__countdown" data-date="@periodEndDate.ToString("MM/dd/yyyy HH:mm:ss")">
<div class="product-item__countdown-title">@Translate("Offer ends in")</div>
<div class="product-item__countdown-counter"></div>
<div class="product-item__countdown-text">
<span>@Translate("Hours", "Hours")</span>
<span>@Translate("Min", "Min")</span>
<span>@Translate("Sec", "Sec")</span>
</div>
</div>
</div>
}
}
<div class="product-item__headline">
<h2 itemprop="name">@product.GetString("Ecom:Product.Name")</h2>
</div>
@if (!string.IsNullOrEmpty(@product.GetString("Ecom:Product.Price.Price")))
{
<div itemprop="offers" itemscope itemtype="http://schema.org/Offer" class="product-item__price">
<link itemprop="availability" href="http://schema.org/InStock">
<link itemprop="url" href="@groupViewModel.UrlService.GetUrl(groupViewModel.Id, product.GetString("Ecom:Product.ID"))" />
@if (!string.IsNullOrEmpty(product.GetString("Ecom:Product:Field.Savepct.Value")))
{
<div class="save">
<span>@Translate("Save", "Save") @product.GetString("Ecom:Product:Field.Savepct.Value")%</span>
</div>
}
<div class="price"><span itemprop="priceCurrency" content="@product.GetString("Ecom:Product.Price.Currency.Symbol")">@product.GetString("Ecom:Product.Price.Currency.Symbol")</span> <span itemprop="price" content="@product.GetDouble("Ecom:Product.Price.PriceWithVAT.Value").ToString("F", new CultureInfo("en-GB"))">@product.GetString("Ecom:Product.Price.Price")</span></div>
<div class="if-discount">
@if (!string.IsNullOrEmpty(product.GetString("Ecom:Product:Field.PriceBefore.Value")))
{
if (product.GetDouble("Ecom:Product:Field.PriceBefore.Value") > 0)
{
<span>@Translate("Before", "Used to be") @product.GetString("Ecom:Product.Price.Currency.Symbol") @product.GetString("Ecom:Product:Field.PriceBefore.Value")</span>
}
}
</div>
</div>
}
<div class="product-item__button">
<span class="btn">
@if (Pageview.AreaID != 2)
{
<span class="btn__icon">
<img src="@groupViewModel.StaticResourceService.AddTimeStamp("/static/dist/media/cart-white-outletcamping.png")">
</span>
}
<span class="btn__text">@Translate("SeeMore", "See more")</span>
</span>
</div>
</div>
</a>
@if (isHero && groupViewModel.HeroImage != null)
{
<figure>
<img src="@groupViewModel.HeroImage.SetWidth(800).SetHeight(400).SetCrop(CropType.KeepAspectRatio).SetCompression(80).GetCrop()" />
</figure>
}
</article>
}
@helper RenderHeroProduct(ProductViewModel productViewModel, GroupViewModel groupViewModel, bool isHero)
{
var productClass = isHero ? "product-item--hero" : "product-item--flex";
<article itemscope itemtype="http://schema.org/Product" class="product-item @productClass">
<a itemprop="url" href="@groupViewModel.UrlService.GetUrl(groupViewModel.Id, productViewModel.Id)">
<div class="product-item__header">
<figure>
<img src="@productViewModel.MainImage.SetWidth(800).SetHeight(800).SetCrop(CropType.KeepAspectRatio).SetCompression(80).GetCrop()" itemprop="image" content="@productViewModel.MainImage.SetWidth(800).SetHeight(800).SetCrop(CropType.KeepAspectRatio).SetCompression(80).GetCrop()" alt="">
</figure>
@if (!string.IsNullOrEmpty(productViewModel.OutletcampingSplash) && !string.IsNullOrEmpty(productViewModel.OutletcampingSplashColor))
{
var splashTexts = productViewModel.OutletcampingSplash.Split(' ');
<div class="product-item__splash product-item__splash" style="background: @productViewModel.OutletcampingSplashColor;">
<div class="product-item__splash-text">
<p>
@for (var i = 0; i <= splashTexts.Length - 1; i++)
{
if (i == 1)
{
<span class="product-item__splash-text--bold"> @splashTexts[i]</span>
}
else
{
@splashTexts[i]
}
}
</p>
</div>
</div>
}
</div>
<div class="product-item__body">
@{
if (productViewModel.PeriodEndDate >= DateTime.Now && productViewModel.PeriodEndDate <= DateTime.Now.AddDays(14))
{
<div data-module="countdown">
<div class="product-item__countdown" data-date="@productViewModel.PeriodEndDate.ToString("MM/dd/yyyy HH:mm:ss")">
<div class="product-item__countdown-title">@Translate("Offer ends in")</div>
<div class="product-item__countdown-counter"></div>
<div class="product-item__countdown-text">
<span>@Translate("Hours", "Hours")</span>
<span>@Translate("Min", "Min")</span>
<span>@Translate("Sec", "Sec")</span>
</div>
</div>
</div>
}
}
<div class="product-item__headline">
<h1 itemprop="name">@productViewModel.Name</h1>
</div>
@if (!string.IsNullOrEmpty(@productViewModel.Price))
{
<div itemprop="offers" itemscope itemtype="http://schema.org/Offer" class="product-item__price">
<div class="price"><span itemprop="priceCurrency" content="@productViewModel.Currency">@productViewModel.CurrencySymbol</span> <span itemprop="price" content="@productViewModel.UnformatedPrice">@productViewModel.Price</span></div>
<div class="if-discount">
@if (!string.IsNullOrEmpty(productViewModel.BeforePrice))
{
<span>@Translate("Before", "Used to be") @productViewModel.CurrencySymbol @productViewModel.BeforePrice</span>
}
</div>
</div>
}
<div class="product-item__button">
<span class="btn">
@if (Pageview.AreaID != 2)
{
<span class="btn__icon">
<img src="@groupViewModel.StaticResourceService.AddTimeStamp("/static/dist/media/cart-white-outletcamping.png")">
</span>
}
<span class="btn__text">@Translate("SeeMore", "See more")</span>
</span>
</div>
</div>
</a>
@if (isHero && groupViewModel.HeroImage != null)
{
<figure>
<img src="@groupViewModel.HeroImage.SetWidth(800).SetHeight(400).SetCrop(CropType.KeepAspectRatio).SetCompression(80).GetCrop()" />
</figure>
}
</article>
}
@SnippetStart("jarvis")
@{
var raptorArea = PageView.Current().Area;
var settingsRaptorApiKey = PageView.Current().Area.Item["SettingsRaptorApiKey"];
}
@if (settingsRaptorApiKey != null)
{
if (PageView.Current().Device == Dynamicweb.Frontend.Devices.DeviceType.Desktop && !string.IsNullOrEmpty(settingsRaptorApiKey.ToString()))
{
var jarvis = (HttpContext.Current.Request.Cookies["jarvis"] != null) ? HttpContext.Current.Request.Cookies["jarvis"].Value : "1";
var jarvisBoxStatus = (jarvis == "1") ? "jarvis--open" : string.Empty;
var jarvisBtnStatus = (jarvis == "1") ? "" : "jarvis-btn--open";
var raptorAreaId = raptorArea.ID;
var raptorBrandId = (raptorArea.Item["SettingsRaptorUserId"] != null) ? raptorArea.Item["SettingsRaptorUserId"].ToString() : string.Empty;
var raptorCookieId = (HttpContext.Current.Request.Cookies[raptorBrandId + "rsa"] != null) ? HttpContext.Current.Request.Cookies[raptorBrandId + "rsa"].Value : "";
var raptorContent1 = groupViewModel.JarvisHistory;
var raptorContent2 = groupViewModel.JarvisTopCategory;
var settingsShopId = raptorArea.Item["SettingsShopId"].ToString();
var ecomPageId = urlParserService.GetPageId(settingsShopId);
if (!string.IsNullOrEmpty(raptorCookieId))
{
<div data-module="jarvis">
<div class="jarvis @jarvisBoxStatus">
<div class="jarvis__header">
<span class="your">@Translate("Your", "Your")</span>
<span class="guide">@Translate("Guide", "Guide")</span>
<span class="logo"></span>
</div>
<div class="jarvis__guide">
<button class="jarvis__close"><span class="round"><svg viewBox="0 0 100 100"><path d="M 10,50 L 60,100 L 70,90 L 30,50 L 70,10 L 60,0 Z" class="arrow"></path></svg></span> @Translate("Hide the wizard", "Hide the wizard")</button>
<div class="jarvis__text">
<p>
@Translate("The guide follows you around and finds new recommendations based on what you're looking at.", "The guide follows you around and finds new recommendations based on what you're looking at.")
</p>
</div>
</div>
<div class="jarvis__alternatives">
<section class="featured-products container-ribbon ribbon">
<h3>@Translate("Most seen in this category", "Most seen in this category")</h3>
<div class="featured-products__container" data-url="/webservices/jarvis.ashx?areaId=@raptorAreaId&raptorFunction=GetTopViewedInCategory&raptorCategoryId=@groupId">
@foreach (var raptorProduct in raptorContent2)
{
var raptorProductView = productViewModelService.GetViewModel(raptorProduct);
if (raptorProductView.MainImage != null)
{
raptorProductView.RaptorImage = raptorProductView.MainImage.SetWidth(500).SetHeight(300).SetCrop(CropType.KeepAspectRatio).SetCompression(50).GetCrop();
}
raptorProductView.RaptorUrl = urlService.GetUrl(raptorProductView.GroupId, raptorProductView.Id, ecomPageId.GetValueOrDefault());
<article itemscope itemtype="http://schema.org/Product\" class="product-item">
<a itemprop="url" href="@raptorProductView.RaptorUrl">
<div class="product-item__header">
<figure>
<img src="@raptorProductView.RaptorImage" itemprop="image" content="OaseOutdoors.Services.ImageService.ImageService" alt="@raptorProductView.Name">
</figure>
</div>
<div class="product-item__body">
<div class="product-item__headline">
<h3 itemprop="name" class="h-1">@raptorProductView.Name</h3>
</div>
<div itemprop="offers" itemscope itemtype="http://schema.org/Offer" class="product-item__price">
<div class="price"><span itemprop=\"priceCurrency\" content="@raptorProductView.Currency">@raptorProductView.CurrencySymbol</span> <span itemprop="price" content="@raptorProductView.UnformatedPrice">@raptorProductView.Price</span></div>
</div>
</div>
</a>
</article>
}
</div>
</section>
</div>
<div class="jarvis__suggest">
<section class="featured-products container-ribbon ribbon">
<h3>@Translate("You have previously looked at", "You have previously looked at")</h3>
<div class="featured-products__container" data-url="/webservices/jarvis.ashx?areaId=@raptorAreaId&raptorFunction=GetCookieHistory">
@foreach (var raptorProduct in raptorContent1)
{
var raptorProductView = productViewModelService.GetViewModel(raptorProduct);
if (raptorProductView.MainImage != null)
{
raptorProductView.RaptorImage = raptorProductView.MainImage.SetWidth(500).SetHeight(300).SetCrop(CropType.KeepAspectRatio).SetCompression(50).GetCrop();
}
raptorProductView.RaptorUrl = urlService.GetUrl(raptorProductView.GroupId, raptorProductView.Id, ecomPageId.GetValueOrDefault());
<article itemscope itemtype="http://schema.org/Product\" class="product-item">
<a itemprop="url" href="@raptorProductView.RaptorUrl">
<div class="product-item__header">
<figure>
<img src="@raptorProductView.RaptorImage" itemprop="image" content="OaseOutdoors.Services.ImageService.ImageService" alt="@raptorProductView.Name">
</figure>
</div>
<div class="product-item__body">
<div class="product-item__headline">
<h3 itemprop="name" class="h-1">@raptorProductView.Name</h3>
</div>
<div itemprop="offers" itemscope itemtype="http://schema.org/Offer" class="product-item__price">
<div class="price"><span itemprop=\"priceCurrency\" content="@raptorProductView.Currency">@raptorProductView.CurrencySymbol</span> <span itemprop="price" content="@raptorProductView.UnformatedPrice">@raptorProductView.Price</span></div>
</div>
</div>
</a>
</article>
}
</div>
</section>
</div>
</div>
<div class="jarvis-btn @jarvisBtnStatus">
<img src="/static/dist/img/jarvis/jarvis-small.png">
</div>
</div>
}
}
}
@SnippetEnd("jarvis")
@functions {
public bool isStringInt(String s)
{
try
{
int.Parse(s);
return true;
}
catch (FormatException ex)
{
return false;
}
}
}