Skip to content

Commit 50334c7

Browse files
Improvement - Category picture - use localizable alternate text and title attributes for a picture
1 parent 7574ca4 commit 50334c7

File tree

10 files changed

+280
-37
lines changed

10 files changed

+280
-37
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
@using Microsoft.AspNetCore.Mvc.Razor;
2+
3+
@model CategoryModel.PictureModel
4+
@{
5+
Layout = Grand.Web.Admin.Extensions.Constants.Layout_AdminPopup;
6+
//page title
7+
ViewBag.Title = Loc["Admin.Catalog.Categories.Picture"];
8+
}
9+
<form asp-area="@Constants.AreaAdmin" asp-controller="Category" asp-action="PicturePopup" enctype="multipart/form-data" method="post"
10+
asp-route-CategoryId="@Context.Request.Query["CategoryId"]">
11+
12+
13+
<!-- #region languages template -->
14+
@{ Func<int, HelperResult> template = @<div class="form-body">
15+
<div class="form-group">
16+
<admin-label asp-for="@Model.Locales[item].AltAttribute" class="col-sm-3 control-label" />
17+
<div class="col-md-9 col-sm-9">
18+
<admin-input asp-for="@Model.Locales[item].AltAttribute" />
19+
<span asp-validation-for="@Model.Locales[item].AltAttribute"></span>
20+
</div>
21+
</div>
22+
<div class="form-group">
23+
<admin-label asp-for="@Model.Locales[item].TitleAttribute" class="col-sm-3 control-label" />
24+
<div class="col-md-9 col-sm-9">
25+
<admin-input asp-for="@Model.Locales[item].TitleAttribute" />
26+
<span asp-validation-for="@Model.Locales[item].TitleAttribute"></span>
27+
</div>
28+
</div>
29+
<input asp-for="@Model.Locales[item].LanguageId" type="hidden" />
30+
</div>;
31+
}
32+
33+
<div asp-validation-summary="All"></div>
34+
<input asp-for="CategoryId" type="hidden" />
35+
<input asp-for="Id" type="hidden" />
36+
<input asp-for="PictureUrl" type="hidden" />
37+
<div class="row">
38+
<div class="col-md-12">
39+
<div class="x_panel light form-fit">
40+
<div class="x_content form">
41+
<div class="form-horizontal">
42+
<div class="form-body">
43+
<div class="form-group">
44+
<admin-label asp-for="PictureUrl" />
45+
<div class="col-md-9 col-sm-9">
46+
<a href="@Model.PictureUrl" target="_blank"><img src="@Model.PictureUrl" width="150" /></a>
47+
</div>
48+
</div>
49+
<localized-editor localized-template=template name="picturevalue-localized" language-ids=@Model.Locales.Select(c=>c.LanguageId).ToList()>
50+
<div class="form-body">
51+
<div class="form-group">
52+
<admin-label asp-for="AltAttribute" class="col-sm-3 control-label" />
53+
<div class="col-md-9 col-sm-9">
54+
<admin-input asp-for="AltAttribute" />
55+
<span asp-validation-for="AltAttribute"></span>
56+
</div>
57+
</div>
58+
<div class="form-group">
59+
<admin-label asp-for="TitleAttribute" class="col-sm-3 control-label" />
60+
<div class="col-md-9 col-sm-9">
61+
<admin-input asp-for="TitleAttribute" />
62+
<span asp-validation-for="TitleAttribute"></span>
63+
</div>
64+
</div>
65+
</div>
66+
</localized-editor>
67+
<div class="form-actions">
68+
<div class="row">
69+
<div class="offset-md-3 offset-sm-3 col-md-9 col-sm-9">
70+
<button class="k-button" type="submit" name="save"><i class="fa fa-check"></i>@Loc["Admin.Common.Save"] </button>
71+
</div>
72+
</div>
73+
</div>
74+
75+
</div>
76+
</div>
77+
</div>
78+
</div>
79+
</div>
80+
</div>
81+
@if (ViewBag.RefreshPage == true)
82+
{
83+
<script>
84+
window.close();
85+
</script>
86+
}
87+
</form>

src/Web/Grand.Web.Admin/Areas/Admin/Views/Category/_CreateOrUpdate.TabInfo.cshtml

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -30,38 +30,38 @@
3030

3131

3232
@{ Func<int, HelperResult>
33-
template = @<div class="form-body">
34-
<div class="form-group">
35-
<admin-label asp-for="@Model.Locales[item].Name" />
36-
<div class="col-md-9 col-sm-9">
37-
<admin-input asp-for="@Model.Locales[item].Name" />
38-
<span asp-validation-for="@Model.Locales[item].Name"></span>
39-
</div>
33+
template = @<div class="form-body">
34+
<div class="form-group">
35+
<admin-label asp-for="@Model.Locales[item].Name" />
36+
<div class="col-md-9 col-sm-9">
37+
<admin-input asp-for="@Model.Locales[item].Name" />
38+
<span asp-validation-for="@Model.Locales[item].Name"></span>
4039
</div>
41-
<div class="form-group">
42-
<admin-label asp-for="@Model.Locales[item].Description" />
43-
<div class="col-md-9 col-sm-9">
44-
<admin-input asp-for="@Model.Locales[item].Description" asp-template="Editor" />
45-
<span asp-validation-for="@Model.Locales[item].Description"></span>
46-
</div>
40+
</div>
41+
<div class="form-group">
42+
<admin-label asp-for="@Model.Locales[item].Description" />
43+
<div class="col-md-9 col-sm-9">
44+
<admin-input asp-for="@Model.Locales[item].Description" asp-template="Editor" />
45+
<span asp-validation-for="@Model.Locales[item].Description"></span>
4746
</div>
48-
<div class="form-group">
49-
<admin-label asp-for="@Model.Locales[item].BottomDescription" />
50-
<div class="col-md-9 col-sm-9">
51-
<admin-input asp-for="@Model.Locales[item].BottomDescription" asp-template="Editor" />
52-
<span asp-validation-for="@Model.Locales[item].BottomDescription"></span>
53-
</div>
47+
</div>
48+
<div class="form-group">
49+
<admin-label asp-for="@Model.Locales[item].BottomDescription" />
50+
<div class="col-md-9 col-sm-9">
51+
<admin-input asp-for="@Model.Locales[item].BottomDescription" asp-template="Editor" />
52+
<span asp-validation-for="@Model.Locales[item].BottomDescription"></span>
5453
</div>
55-
<div class="form-group">
56-
<admin-label asp-for="@Model.Locales[item].Flag" />
57-
<div class="col-md-9 col-sm-9">
58-
<admin-input asp-for="@Model.Locales[item].Flag" />
59-
<span asp-validation-for="@Model.Locales[item].Flag"></span>
60-
</div>
54+
</div>
55+
<div class="form-group">
56+
<admin-label asp-for="@Model.Locales[item].Flag" />
57+
<div class="col-md-9 col-sm-9">
58+
<admin-input asp-for="@Model.Locales[item].Flag" />
59+
<span asp-validation-for="@Model.Locales[item].Flag"></span>
6160
</div>
62-
<input type="hidden" asp-for="@Model.Locales[item].LanguageId" />
63-
</div>;
64-
}
61+
</div>
62+
<input type="hidden" asp-for="@Model.Locales[item].LanguageId" />
63+
</div>;
64+
}
6565
<div class="form-horizontal">
6666
<vc:admin-widget widget-zone="category_details_info_top" additional-data="Model" />
6767
<localized-editor localized-template=@template name="category-info-localized" language-ids=@Model.Locales.Select(c=>c.LanguageId).ToList()>
@@ -141,6 +141,12 @@
141141
<div class="col-md-9 col-sm-9">
142142
<admin-input asp-for="PictureId" />
143143
<span asp-validation-for="PictureId"></span>
144+
@if (!string.IsNullOrEmpty(Model.PictureId))
145+
{
146+
<label class="control-label">
147+
<a class='k-link' href='javascript:OpenWindow("@Url.Action("PicturePopup", "Category", new { area = Constants.AreaAdmin })/?categoryId=@(Model.Id)", 800, 600, true);'>@Loc["Admin.Common.Picture.Attributes"]</a>
148+
</label>
149+
}
144150
</div>
145151
</div>
146152
<div class="form-group">

src/Web/Grand.Web.Admin/Controllers/CategoryController.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,60 @@ public async Task<IActionResult> Delete(string id)
252252
}
253253

254254

255+
#endregion
256+
257+
#region Picture
258+
259+
[PermissionAuthorizeAction(PermissionActionName.Preview)]
260+
public async Task<IActionResult> PicturePopup(string categoryId)
261+
{
262+
var category = await _categoryService.GetCategoryById(categoryId);
263+
if (category == null)
264+
return Content("Category not exist");
265+
266+
if (string.IsNullOrEmpty(category.PictureId))
267+
return Content("Picture not exist");
268+
269+
var permission = await CheckAccessToCategory(category);
270+
if (!permission.allow)
271+
return Content(permission.message);
272+
273+
274+
var (model, picture) = await _categoryViewModelService.PreparePictureModel(category);
275+
//locales
276+
await AddLocales(_languageService, model.Locales, (locale, languageId) =>
277+
{
278+
locale.AltAttribute = picture?.GetTranslation(x => x.AltAttribute, languageId, false);
279+
locale.TitleAttribute = picture?.GetTranslation(x => x.TitleAttribute, languageId, false);
280+
});
281+
282+
return View(model);
283+
}
284+
285+
[PermissionAuthorizeAction(PermissionActionName.Edit)]
286+
[HttpPost]
287+
public async Task<IActionResult> PicturePopup(CategoryModel.PictureModel model)
288+
{
289+
if (ModelState.IsValid)
290+
{
291+
var category = await _categoryService.GetCategoryById(model.CategoryId);
292+
if (category == null)
293+
throw new ArgumentException("No category found with the specified id");
294+
295+
if (string.IsNullOrEmpty(category.PictureId))
296+
throw new ArgumentException("No picture found with the specified id");
297+
298+
await _categoryViewModelService.UpdateCategoryPicture(model);
299+
300+
ViewBag.RefreshPage = true;
301+
return View(model);
302+
}
303+
304+
Error(ModelState);
305+
306+
return View(model);
307+
}
308+
255309
#endregion
256310

257311
#region Export / Import

src/Web/Grand.Web.Admin/Interfaces/ICategoryViewModelService.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Grand.Domain.Catalog;
2+
using Grand.Domain.Media;
23
using Grand.Web.Admin.Models.Catalog;
34
using System.Collections.Generic;
45
using System.Threading.Tasks;
@@ -14,6 +15,8 @@ public interface ICategoryViewModelService
1415
Task<Category> InsertCategoryModel(CategoryModel model);
1516
Task<Category> UpdateCategoryModel(Category category, CategoryModel model);
1617
Task DeleteCategory(Category category);
18+
Task<(CategoryModel.PictureModel model, Picture Picture)> PreparePictureModel(Category category);
19+
Task UpdateCategoryPicture(CategoryModel.PictureModel model);
1720
Task<(IEnumerable<CategoryModel.CategoryProductModel> categoryProductModels, int totalCount)> PrepareCategoryProductModel(string categoryId, int pageIndex, int pageSize);
1821
Task<ProductCategory> UpdateProductCategoryModel(CategoryModel.CategoryProductModel model);
1922
Task DeleteProductCategoryModel(string id, string productId);

src/Web/Grand.Web.Admin/Models/Catalog/CategoryModel.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,37 @@ public partial class ActivityLogModel : BaseEntityModel
192192
public string CustomerEmail { get; set; }
193193
}
194194

195+
public partial class PictureModel : BaseEntityModel, ILocalizedModel<PictureModel.PictureLocalizedModel>
196+
{
197+
public PictureModel()
198+
{
199+
Locales = new List<PictureLocalizedModel>();
200+
}
201+
202+
public string CategoryId { get; set; }
203+
204+
[GrandResourceDisplayName("Admin.Catalog.Categories.Picture")]
205+
public string PictureUrl { get; set; }
206+
207+
[GrandResourceDisplayName("Admin.Catalog.Categories.Picture.Fields.AltAttribute")]
208+
public string AltAttribute { get; set; }
209+
210+
[GrandResourceDisplayName("Admin.Catalog.Categories.Picture.Fields.TitleAttribute")]
211+
public string TitleAttribute { get; set; }
212+
213+
public IList<PictureLocalizedModel> Locales { get; set; }
214+
215+
public partial class PictureLocalizedModel : ILocalizedModelLocal
216+
{
217+
public string LanguageId { get; set; }
218+
219+
[GrandResourceDisplayName("Admin.Catalog.Categories.Picture.Fields.AltAttribute")]
220+
public string AltAttribute { get; set; }
221+
222+
[GrandResourceDisplayName("Admin.Catalog.Categories.Picture.Fields.TitleAttribute")]
223+
public string TitleAttribute { get; set; }
224+
}
225+
}
195226

196227
#endregion
197228
}

src/Web/Grand.Web.Admin/Services/CategoryViewModelService.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using System.Collections.Generic;
2323
using System.Linq;
2424
using System.Threading.Tasks;
25+
using Grand.Domain.Media;
2526

2627
namespace Grand.Web.Admin.Services
2728
{
@@ -34,7 +35,6 @@ public partial class CategoryViewModelService : ICategoryViewModelService
3435
private readonly ITranslationService _translationService;
3536
private readonly IStoreService _storeService;
3637
private readonly ICustomerService _customerService;
37-
private readonly IGroupService _groupService;
3838
private readonly ISlugService _slugService;
3939
private readonly IPictureService _pictureService;
4040
private readonly ICustomerActivityService _customerActivityService;
@@ -46,7 +46,7 @@ public partial class CategoryViewModelService : ICategoryViewModelService
4646
private readonly SeoSettings _seoSettings;
4747

4848
public CategoryViewModelService(ICategoryService categoryService, IProductCategoryService productCategoryService, ICategoryLayoutService categoryLayoutService, IDiscountService discountService,
49-
ITranslationService translationService, IStoreService storeService, ICustomerService customerService, IGroupService groupService, IPictureService pictureService,
49+
ITranslationService translationService, IStoreService storeService, ICustomerService customerService, IPictureService pictureService,
5050
ISlugService slugService, ICustomerActivityService customerActivityService, IProductService productService,
5151
IVendorService vendorService, IDateTimeService dateTimeService, ILanguageService languageService, CatalogSettings catalogSettings, SeoSettings seoSettings)
5252
{
@@ -57,7 +57,6 @@ public CategoryViewModelService(ICategoryService categoryService, IProductCatego
5757
_translationService = translationService;
5858
_storeService = storeService;
5959
_customerService = customerService;
60-
_groupService = groupService;
6160
_slugService = slugService;
6261
_customerActivityService = customerActivityService;
6362
_productService = productService;
@@ -248,6 +247,31 @@ public virtual async Task DeleteCategory(Category category)
248247
//activity log
249248
await _customerActivityService.InsertActivity("DeleteCategory", category.Id, _translationService.GetResource("ActivityLog.DeleteCategory"), category.Name);
250249
}
250+
251+
public virtual async Task<(CategoryModel.PictureModel model, Picture Picture)> PreparePictureModel(Category category)
252+
{
253+
var picture = await _pictureService.GetPictureById(category.PictureId);
254+
var model = new CategoryModel.PictureModel {
255+
Id = picture.Id,
256+
CategoryId = category.Id,
257+
PictureUrl = picture != null ? await _pictureService.GetPictureUrl(picture) : null,
258+
AltAttribute = picture?.AltAttribute,
259+
TitleAttribute = picture?.TitleAttribute,
260+
};
261+
return (model, picture);
262+
}
263+
public virtual async Task UpdateCategoryPicture(CategoryModel.PictureModel model)
264+
{
265+
var picture = await _pictureService.GetPictureById(model.Id);
266+
if (picture == null)
267+
throw new ArgumentException("No picture found with the specified id");
268+
269+
//Update picture fields
270+
await _pictureService.UpdatField(picture, x => x.AltAttribute, model.AltAttribute);
271+
await _pictureService.UpdatField(picture, x => x.TitleAttribute, model.TitleAttribute);
272+
await _pictureService.UpdatField(picture, x => x.Locales, model.Locales.ToTranslationProperty());
273+
274+
}
251275
public virtual async Task<(IEnumerable<CategoryModel.CategoryProductModel> categoryProductModels, int totalCount)> PrepareCategoryProductModel(string categoryId, int pageIndex, int pageSize)
252276
{
253277
var productCategories = await _productCategoryService.GetProductCategoriesByCategoryId(categoryId,

src/Web/Grand.Web/App_Data/Resources/DefaultLanguage.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2301,6 +2301,15 @@
23012301
<Resource Name="Admin.Catalog.Categories.Permisions">
23022302
<Value>You can't edit this category, because it can be used in many stores.</Value>
23032303
</Resource>
2304+
<Resource Name="Admin.Catalog.Categories.Picture">
2305+
<Value>Picture</Value>
2306+
</Resource>
2307+
<Resource Name="Admin.Catalog.Categories.Picture.Fields.AltAttribute">
2308+
<Value>Picture alternate text</Value>
2309+
</Resource>
2310+
<Resource Name="Admin.Catalog.Categories.Picture.Fields.TitleAttribute">
2311+
<Value>Picture title</Value>
2312+
</Resource>
23042313
<Resource Name="Admin.Catalog.Categories.Products">
23052314
<Value>Products</Value>
23062315
</Resource>
@@ -3906,6 +3915,9 @@
39063915
<Resource Name="Admin.Common.NoCancel">
39073916
<Value>No, cancel</Value>
39083917
</Resource>
3918+
<Resource Name="Admin.Common.Picture.Attributes">
3919+
<Value>Picture attributes</Value>
3920+
</Resource>
39093921
<Resource Name="Admin.Common.Preview">
39103922
<Value>Show in the shop page</Value>
39113923
</Resource>

0 commit comments

Comments
 (0)