Skip to content

Commit

Permalink
#1161 #180 Allow a store owner to choose available "sort by" options
Browse files Browse the repository at this point in the history
  • Loading branch information
RomanovM committed Feb 4, 2016
1 parent 38d347d commit 29648f9
Show file tree
Hide file tree
Showing 14 changed files with 378 additions and 9 deletions.
2 changes: 2 additions & 0 deletions src/Libraries/Nop.Core/CommonHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ public static TypeConverter GetNopCustomTypeConverter(Type type)
return new ShippingOptionTypeConverter();
if (type == typeof(List<ShippingOption>) || type == typeof(IList<ShippingOption>))
return new ShippingOptionListTypeConverter();
if (type == typeof(Dictionary<int, int>))
return new GenericDictionaryTypeConverter<int, int>();

return TypeDescriptor.GetConverter(type);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;

namespace Nop.Core.ComponentModel
{
/// <summary>
/// Generic Dictionary type converted
/// </summary>
/// <typeparam name="K">Key type (simple)</typeparam>
/// <typeparam name="V">Value type (simple)</typeparam>
public class GenericDictionaryTypeConverter<K, V> : TypeConverter
{
protected readonly TypeConverter typeConverterKey;
protected readonly TypeConverter typeConverterValue;

/// <summary>
/// Ctor
/// </summary>
public GenericDictionaryTypeConverter()
{
typeConverterKey = TypeDescriptor.GetConverter(typeof(K));
if (typeConverterKey == null)
throw new InvalidOperationException("No type converter exists for type " + typeof(K).FullName);
typeConverterValue = TypeDescriptor.GetConverter(typeof(V));
if (typeConverterValue == null)
throw new InvalidOperationException("No type converter exists for type " + typeof(V).FullName);
}

/// <summary>
/// Gets a value indicating whether this converter can
/// convert an object in the given source type to the native type of the converter
/// using the context.
/// </summary>
/// <param name="context">Context</param>
/// <param name="sourceType">Source type</param>
/// <returns>Result</returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;

return base.CanConvertFrom(context, sourceType);
}

/// <summary>
/// Converts the given object to the converter's native type.
/// </summary>
/// <param name="context">Context</param>
/// <param name="culture">Culture</param>
/// <param name="value">Value</param>
/// <returns>Result</returns>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
string input = (string)value;
string[] items = string.IsNullOrEmpty(input) ? new string[0] : input.Split(';').Select(x => x.Trim()).ToArray();

var result = new Dictionary<K,V>();
Array.ForEach(items, s =>
{
string[] keyValueStr = string.IsNullOrEmpty(s) ? new string[0] : s.Split(',').Select(x => x.Trim()).ToArray();
if (keyValueStr.Length == 2)
{
object dictionaryKey = (K)typeConverterKey.ConvertFromInvariantString(keyValueStr[0]);
object dictionaryValue = typeConverterKey.ConvertFromInvariantString(keyValueStr[1]);
if (dictionaryKey != null && dictionaryValue != null)
{
if (!result.ContainsKey((K)dictionaryKey))
result.Add((K) dictionaryKey, (V) dictionaryValue);
}
}
});

return result;
}
return base.ConvertFrom(context, culture, value);
}

/// <summary>
/// Converts the given value object to the specified destination type using the specified context and arguments
/// </summary>
/// <param name="context">Context</param>
/// <param name="culture">Culture</param>
/// <param name="value">Value</param>
/// <param name="destinationType">Destination type</param>
/// <returns>Result</returns>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
string result = string.Empty;
if (value != null)
{
//we don't use string.Join() because it doesn't support invariant culture
int counter = 0;
var dictionary = (IDictionary<K, V>)value;
foreach (var keyValue in dictionary)
{
result += string.Format("{0}, {1}", Convert.ToString(keyValue.Key, CultureInfo.InvariantCulture), Convert.ToString(keyValue.Value, CultureInfo.InvariantCulture));
//don't add ; after the last element
if (counter != dictionary.Count - 1)
result += ";";
counter++;
}
}
return result;
}

return base.ConvertTo(context, culture, value, destinationType);
}
}
}
19 changes: 18 additions & 1 deletion src/Libraries/Nop.Core/Domain/Catalog/CatalogSettings.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Nop.Core.Configuration;
using System.Collections.Generic;
using Nop.Core.Configuration;

namespace Nop.Core.Domain.Catalog
{
Expand All @@ -7,6 +8,12 @@ namespace Nop.Core.Domain.Catalog
/// </summary>
public class CatalogSettings : ISettings
{
public CatalogSettings()
{
ProductSortingEnumDisabled = new List<int>();
ProductSortingEnumDisplayOrder= new Dictionary<int, int>();
}

/// <summary>
/// Gets or sets a value indicating details pages of unpublished product details pages could be open (for SEO optimization)
/// </summary>
Expand Down Expand Up @@ -307,5 +314,15 @@ public class CatalogSettings : ISettings
/// Gets or sets the default value to use for Manufacturer page size (for new manufacturers)
/// </summary>
public int DefaultManufacturerPageSize { get; set; }

/// <summary>
/// Gets or sets a list of disabled values of ProductSortingEnum
/// </summary>
public List<int> ProductSortingEnumDisabled { get; set; }

/// <summary>
/// Gets or sets a display order of ProductSortingEnum values
/// </summary>
public Dictionary<int, int> ProductSortingEnumDisplayOrder { get; set; }
}
}
1 change: 1 addition & 0 deletions src/Libraries/Nop.Core/Nop.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Caching\RedisCacheManager.cs" />
<Compile Include="ComponentModel\GenericDictionaryTypeConverter.cs" />
<Compile Include="ComponentModel\WriteLockDisposable.cs" />
<Compile Include="Domain\Catalog\Events.cs" />
<Compile Include="Domain\Catalog\PredefinedProductAttributeValue.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4666,7 +4666,12 @@ protected virtual void InstallSettings()
DefaultCategoryPageSizeOptions = "6, 3, 9",
DefaultCategoryPageSize = 6,
DefaultManufacturerPageSizeOptions = "6, 3, 9",
DefaultManufacturerPageSize = 6
DefaultManufacturerPageSize = 6,
ProductSortingEnumDisabled = new List<int>(),
ProductSortingEnumDisplayOrder = new Dictionary<int, int>()
{
{ 0, 1 }, { 5, 2 }, { 6, 3 }, { 10, 4 }, { 11, 5 }, { 15, 6 }
}
});

settingService.SaveSetting(new LocalizationSettings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1371,7 +1371,58 @@ public ActionResult Catalog(CatalogSettingsModel model)
return RedirectToAction("Catalog");
}

#region Sort options

[HttpPost]
public ActionResult SortOptionsList(DataSourceRequest command)
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
return AccessDeniedView();

var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext);
var catalogSettings = _settingService.LoadSetting<CatalogSettings>(storeScope);
var model = new List<SortOptionModel>();
foreach (var option in catalogSettings.ProductSortingEnumDisplayOrder)
{
model.Add(new SortOptionModel()
{
Id = option.Key,
Name = ((ProductSortingEnum)option.Key).GetLocalizedEnum(_localizationService, _workContext),
IsActive = !catalogSettings.ProductSortingEnumDisabled.Contains(option.Key),
DisplayOrder = option.Value
});
}
var gridModel = new DataSourceResult
{
Data = model,
Total = model.Count
};
return Json(gridModel);
}

[HttpPost]
public ActionResult SortOptionUpdate(SortOptionModel model)
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
return AccessDeniedView();

var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext);
var catalogSettings = _settingService.LoadSetting<CatalogSettings>(storeScope);

catalogSettings.ProductSortingEnumDisplayOrder[model.Id] = model.DisplayOrder;
if (model.IsActive && catalogSettings.ProductSortingEnumDisabled.Contains(model.Id))
catalogSettings.ProductSortingEnumDisabled.Remove(model.Id);
if (!model.IsActive && !catalogSettings.ProductSortingEnumDisabled.Contains(model.Id))
catalogSettings.ProductSortingEnumDisabled.Add(model.Id);

_settingService.SaveSetting(catalogSettings, x => x.ProductSortingEnumDisabled, storeScope, false);
_settingService.SaveSetting(catalogSettings, x => x.ProductSortingEnumDisplayOrder, storeScope, false);
_settingService.ClearCache();

return new NullJsonResult();
}

#endregion

public ActionResult RewardPoints()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,9 @@ public void Execute()
.ForMember(dest => dest.DefaultCategoryPageSizeOptions, mo => mo.Ignore())
.ForMember(dest => dest.DefaultCategoryPageSize, mo => mo.Ignore())
.ForMember(dest => dest.DefaultManufacturerPageSizeOptions, mo => mo.Ignore())
.ForMember(dest => dest.DefaultManufacturerPageSize, mo => mo.Ignore());
.ForMember(dest => dest.DefaultManufacturerPageSize, mo => mo.Ignore())
.ForMember(dest => dest.ProductSortingEnumDisabled, mo => mo.Ignore())
.ForMember(dest => dest.ProductSortingEnumDisplayOrder, mo => mo.Ignore());
Mapper.CreateMap<RewardPointsSettings, RewardPointsSettingsModel>()
.ForMember(dest => dest.PrimaryStoreCurrencyCode, mo => mo.Ignore())
.ForMember(dest => dest.ActiveStoreScopeConfiguration, mo => mo.Ignore())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Web.Mvc;
using Nop.Web.Framework;
using Nop.Web.Framework.Mvc;

namespace Nop.Admin.Models.Settings
{
public partial class SortOptionModel : BaseNopEntityModel
{
[NopResourceDisplayName("Admin.Configuration.Settings.Catalog.SortOptions.Name")]
[AllowHtml]
public string Name { get; set; }

[NopResourceDisplayName("Admin.Configuration.Settings.Catalog.SortOptions.IsActive")]
[AllowHtml]
public bool IsActive { get; set; }

[NopResourceDisplayName("Admin.Configuration.Settings.Catalog.SortOptions.DisplayOrder")]
public int DisplayOrder { get; set; }
}
}
1 change: 1 addition & 0 deletions src/Presentation/Nop.Web/Administration/Nop.Admin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@
<Compile Include="Models\Plugins\PluginListModel.cs" />
<Compile Include="Models\Settings\ReturnRequestActionModel.cs" />
<Compile Include="Models\Settings\ReturnRequestReasonModel.cs" />
<Compile Include="Models\Settings\SortOptionModel.cs" />
<Compile Include="Models\Settings\VendorSettingsModel.cs" />
<Compile Include="Models\Shipping\WarehouseModel.cs" />
<Compile Include="Models\Shipping\DeliveryDateModel.cs" />
Expand Down

0 comments on commit 29648f9

Please sign in to comment.