Bootstrap reload theme, public bidbox logics, html and csss improvements

This commit is contained in:
Adam 2024-11-20 10:40:03 +01:00
parent dfdccd2551
commit 52bf5215b1
300 changed files with 58998 additions and 1905 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,107 @@
body {
font: normal 9pt Arial, Helvetica, sans-serif;
color: #000;
}
table {
width: 100%;
border: 0;
border-collapse: collapse;
border-spacing: 0;
}
li {
list-style: none;
}
a {
color: inherit;
}
.order-details-page .order-overview {
margin: 0 0 25px;
}
.order-details-page .order-overview .order-number {
font-size: 11pt;
text-transform: uppercase;
padding: 10px 40px;
}
.order-details-page .order-overview .order-total {
margin: 10px 0 0;
}
.order-details-page .order-overview .order-total strong {
font-size: 10pt;
}
.order-details-page .order-details-area {
margin: 0 0 25px;
overflow: hidden;
}
.order-details-page .order-details-area ul {
padding-left: 0px;
}
.order-details-page .order-details-area > div {
float: left;
width: 48%;
margin: 0 1% 40px;
}
.order-details-page .order-details-area li.title {
margin: 10px 0 5px;
font-weight: bold;
}
.order-details-page .order-details-area li:first-child {
margin-top: 0;
}
.order-details-page .data-table {
border: 1px solid;
}
.order-details-page .data-table th {
border-right: 1px solid;
border-bottom: 1px solid;
padding: 5px 10px;
font-weight: bold;
white-space: nowrap;
}
.order-details-page .data-table td {
border-right: 1px solid;
border-bottom: 1px solid;
padding: 5px 10px;
}
.order-details-page .data-table .sku,
.order-details-page .data-table .unit-price,
.order-details-page .data-table .quantity,
.order-details-page .data-table .total {
white-space: nowrap;
text-align: center;
}
.order-details-page .data-table .unit-price,
.order-details-page .data-table .quantity,
.order-details-page .data-table .total {
width: 15%;
}
.order-details-page .data-table label {
display: none;
}
.order-details-page .section {
margin: 30px 0;
}
.order-details-page .section .title {
margin: 0 0 10px;
}
.order-details-page .tax-shipping-info,
.order-details-page .selected-checkout-attributes {
margin: 20px 0;
text-align:right;
}
.order-details-page .cart-total-right {
white-space: nowrap;
}
.order-details-page .cart-total td {
padding: 5px 10px;
text-align: right;
}
.order-details-page td.cart-total-left {
width: 100%;
font-weight: bold;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 985 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 987 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 989 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1023 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1022 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1002 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 965 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 989 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 990 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1022 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1023 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 959 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 980 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,107 @@
@model CustomerBackInStockSubscriptionsModel
@using Nop.Core.Domain.Catalog
@{
Layout = "_ColumnsTwo";
//title
NopHtml.AddTitleParts(T("PageTitle.BackInStockSubscriptions").Text);
//page class
NopHtml.AppendPageCssClassParts("html-account-page");
NopHtml.AppendPageCssClassParts("html-back-in-stock-subscription-list-page");
}
@section left
{
@await Component.InvokeAsync(typeof(CustomerNavigationViewComponent), new { selectedTabId = CustomerNavigationEnum.BackInStockSubscriptions })
}
<div class="page account-page back-in-stock-subscription-list-page">
<div class="page-title">
<h1>@T("Account.MyAccount") - @T("Account.BackInStockSubscriptions")</h1>
</div>
<div class="page-body">
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.CustomerBackInStockSubscriptionsTop, additionalData = Model })
@if (Model.Subscriptions.Count > 0)
{
<div class="description alert alert-info">
@T("Account.BackInStockSubscriptions.Description")
</div>
<script asp-location="Footer">
$(function () {
$('#selectall').on('click', function () {
$('.subscription-list .rowcheckbox').prop('checked', $(this).is(':checked')).trigger('change');
});
$('.subscription-list .rowcheckbox').on('change', function (e) {
var numChkBoxes = $('.subscription-list .rowcheckbox').length;
var numChkBoxesChecked = $('.subscription-list .rowcheckbox:checked').length;
$('#selectall').prop('checked', numChkBoxes == numChkBoxesChecked && numChkBoxes > 0);
});
});
</script>
<form asp-route="CustomerBackInStockSubscriptions" method="post">
<div class="subscription-list">
<div class="table-wrapper">
<table class="data-table table table-bordered table-hover">
<colgroup>
<col width="1" />
<col />
</colgroup>
<thead>
<tr>
<th class="select-boxes">
<div class="form-check m-0">
<input class="form-check-input" type="checkbox" id="selectall" />
<label for="selectall" class="form-check-label"></label>
</div>
</th>
<th class="product">
@T("Account.BackInStockSubscriptions.ProductColumn")
</th>
</tr>
</thead>
<tbody>
@for (var i = 0; i < Model.Subscriptions.Count; i++)
{
var item = Model.Subscriptions[i];
<tr @(i % 2 == 0 ? Html.Raw(" class=\"odd\"") : Html.Raw(" class=\"even\""))>
<td class="select-boxes">
<div class="form-check m-0">
<input type="checkbox" name="biss@(item.Id)" class="rowcheckbox form-check-input" />
<label for="biss@(item.Id)" class="form-check-label"></label>
</div>
</td>
<td class="product">
<a href="@(Url.RouteUrl<Product>(new { SeName = item.SeName }))">@item.ProductName</a>
</td>
</tr>
}
</tbody>
</table>
</div>
@{
var pager = await Html.PagerAsync(Model.PagerModel);
}
@if (!string.IsNullOrEmpty(await pager.RenderHtmlContentAsync()))
{
<div class="pagination justify-content-center">
@pager
</div>
}
<div class="buttons">
<button type="submit" name="save" class="btn btn-primary button-1 delete-selected-biss-button">@T("Account.BackInStockSubscriptions.DeleteSelected")</button>
</div>
</div>
</form>
}
else
{
<div class="no-data">
<div class="alert alert-danger">
@T("Account.BackInStockSubscriptions.NoSubscriptions")
</div>
</div>
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.CustomerBackInStockSubscriptionsBottom, additionalData = Model })
</div>
</div>

View File

@ -0,0 +1,69 @@
@model BackInStockSubscribeModel
<div class="page back-in-stock-subscription-page">
<div class="page-title">
<h1>
@if (Model.AlreadySubscribed)
{
@T("BackInStockSubscriptions.AlreadySubscribed")
}
else
{
@T("BackInStockSubscriptions.PopupTitle")
}
</h1>
</div>
<div class="page-body">
@if (!Model.SubscriptionAllowed)
{
<div>
@T("BackInStockSubscriptions.NotAllowed")
</div>
}
else if (!Model.IsCurrentCustomerRegistered)
{
<div>
@T("BackInStockSubscriptions.OnlyRegistered")
</div>
}
else if (!Model.AlreadySubscribed && Model.CurrentNumberOfBackInStockSubscriptions >= Model.MaximumBackInStockSubscriptions)
{
<div>
@string.Format(T("BackInStockSubscriptions.MaxSubscriptions").Text, Model.MaximumBackInStockSubscriptions)
</div>
}
else
{
if (!Model.AlreadySubscribed)
{
<div class="tooltip">@T("BackInStockSubscriptions.Tooltip")</div>
}
<button type="submit" id="back-in-stock-notify-me" class="btn btn-primary button-1 notify-me-button">
@(Model.AlreadySubscribed ? @T("BackInStockSubscriptions.Unsubscribe").Text : @T("BackInStockSubscriptions.NotifyMe").Text)
</button>
<nop-antiforgery-token />
<script>
$(function () {
$("#back-in-stock-notify-me").on('click', function () {
var subscribeButton = this;
var postData = {};
addAntiForgeryToken(postData);
$.ajax({
cache: false,
type: "POST",
data: postData,
url: "@(Url.RouteUrl("BackInStockSubscribeSend", new { productId = Model.ProductId }))",
success: function (data, textStatus, jqXHR) {
$(subscribeButton).closest('.ui-dialog-content').dialog('destroy').remove();
location.reload();
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Failed to change subscription.');
}
});
});
});
</script>
}
</div>
</div>

View File

@ -0,0 +1,165 @@
@inject Nop.Services.Html.IHtmlFormatter htmlFormatter
@model BlogPostModel
@{
Layout = "_ColumnsTwo";
//title
NopHtml.AddTitleParts(!string.IsNullOrEmpty(Model.MetaTitle) ? Model.MetaTitle : Model.Title);
//meta
NopHtml.AddMetaDescriptionParts(Model.MetaDescription);
NopHtml.AddMetaKeywordParts(Model.MetaKeywords);
//page class
NopHtml.AppendPageCssClassParts("html-blogpost-page");
}
@section left {
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.LeftSideColumnBlogBefore, additionalData = Model })
@await Component.InvokeAsync(typeof(BlogMonthsViewComponent))
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.LeftSideColumnAfterBlogArchive, additionalData = Model })
@await Component.InvokeAsync(typeof(BlogTagsViewComponent))
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.LeftSideColumnBlogAfter, additionalData = Model })
}
<div class="page blogpost-page">
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BlogPostPageTop, additionalData = Model })
<div class="page-title">
<h1>@Model.Title</h1>
</div>
<div class="page-body">
<div class="post-date">
@Model.CreatedOn.ToString("D")
</div>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BlogPostPageBeforeBody, additionalData = Model })
<div class="post-body">
@Html.Raw(Model.Body)
</div>
@if (Model.Tags.Count > 0)
{
<div class="tags">
<label>@T("Blog.Tags"):</label>
<ul>
@for (var i = 0; i < Model.Tags.Count; i++)
{
var tag = Model.Tags[i];
<li><a href="@Url.RouteUrl("BlogByTag", new {tag = tag})">@tag</a></li>
if (i != Model.Tags.Count - 1)
{
<li class="separator">,</li>
}
}
</ul>
</div>
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BlogPostPageBeforeComments, additionalData = Model })
@if (Model.AllowComments)
{
<div class="fieldset new-comment" id="comments">
<div class="title">
<strong>@T("Blog.Comments.LeaveYourComment")</strong>
</div>
<div class="notifications">
<div asp-validation-summary="ModelOnly" class="message-error"></div>
@{
var result = TempData["nop.blog.addcomment.result"] as string;
}
@if (!string.IsNullOrEmpty(result))
{
<div class="result">@result</div>
}
</div>
<form asp-controller="Blog" asp-action="BlogCommentAdd" asp-route-blogpostid="@Model.Id" method="post">
<div class="form-fields">
<div class="row mb-3">
<label asp-for="AddNewComment.CommentText" asp-postfix=":" class="col-sm-12 col-md-4 col-lg-4 col-xl-4 col-form-label pl-0 pr-0"></label>
<div class="col-sm-12 col-md-5 col-lg-5 col-xl-5">
<textarea asp-for="AddNewComment.CommentText" class="enter-comment-text form-control" asp-disabled="@Model.PreventNotRegisteredUsersToLeaveComments"></textarea>
<nop-required />
</div>
<div class="col-sm-12 col-md-3 col-lg-3 col-xl-3">
<span asp-validation-for="AddNewComment.CommentText"></span>
</div>
</div>
@if (Model.AddNewComment.DisplayCaptcha)
{
<div class="row mb-3">
<div class="offset-md-4 offset-lg-4 offset-xl-4 col-md-5 col-lg-5 col-xl-5">
<div class="captcha-box">
<nop-captcha action-name="BlogCommentAdd" />
</div>
</div>
</div>
}
</div>
@if (!Model.PreventNotRegisteredUsersToLeaveComments)
{
<div class="row">
<div class="offset-md-4 offset-lg-4 offset-xl-4 col-md-5 col-lg-5 col-xl-5">
<div class="buttons">
<button type="submit" name="add-comment" class="btn btn-primary button-1 blog-post-add-comment-button">@T("Blog.Comments.SubmitButton")</button>
</div>
</div>
</div>
}
else
{
<div class="message-error">@T("Blog.Comments.OnlyRegisteredUsersLeaveComments")</div>
}
</form>
</div>
if (Model.Comments.Count > 0)
{
<div class="comment-list">
<div class="title">
<strong>@T("Blog.Comments")</strong>
</div>
<div class="comments">
@foreach (var comment in Model.Comments)
{
<div class="comment blog-comment">
<div class="comment-info">
<div class="user-info">
@if (comment.AllowViewingProfiles)
{
<a href="@Url.RouteUrl("CustomerProfile", new {id = comment.CustomerId})" class="username">@(comment.CustomerName)</a>
}
else
{
<span class="username">@(comment.CustomerName)</span>
}
@if (!string.IsNullOrEmpty(comment.CustomerAvatarUrl))
{
<div class="avatar">
@if (comment.AllowViewingProfiles)
{
<a href="@Url.RouteUrl("CustomerProfile", new {id = comment.CustomerId})" class="avatar-img-link">
<img src="@(comment.CustomerAvatarUrl)" class="avatar-img" alt="avatar" />
</a>
}
else
{
<img src="@(comment.CustomerAvatarUrl)" class="avatar-img" alt="avatar" />
}
</div>
}
</div>
</div>
<div class="comment-content">
<div class="comment-time">
<label>@T("Blog.Comments.CreatedOn"):</label>
<span class="stat-value">@comment.CreatedOn.ToString("g")</span>
</div>
<div class="comment-body">
@Html.Raw(htmlFormatter.FormatText(comment.CommentText, false, true, false, false, false, false))
</div>
</div>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BlogPostPageInsideComment, additionalData = comment })
</div>
}
</div>
</div>
}
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BlogPostPageAfterComments, additionalData = Model })
</div>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BlogPostPageBottom, additionalData = Model })
</div>

View File

@ -0,0 +1,30 @@
@model IList<BlogPostYearModel>
@if (Model.Count > 0)
{
<div class="block block-blog-archive card">
<div class="card-header title">
<h4>@T("Blog.Archive")</h4>
</div>
<div class="listbox">
<ul class="list-group list-group-flush" id="blog-month-list">
@foreach (var yearItem in Model)
{
<li class="list-group-item year">
<strong class="number">@(yearItem.Year)</strong>
<ul class="list-group list-group-flush sublist" id="blog-year-@(yearItem.Year)">
@foreach (var monthItem in yearItem.Months)
{
<li class="list-group-item month">
<a href="@Url.RouteUrl("BlogByMonth", new { month = yearItem.Year + "-" + monthItem.Month })">
<i class="fa fa-angle-double-right" aria-hidden="true"></i> @(new DateTime(yearItem.Year, monthItem.Month, 1).ToString("MMMM"))
(@(monthItem.BlogPostCount))
</a>
</li>
}
</ul>
</li>
}
</ul>
</div>
</div>
}

View File

@ -0,0 +1,19 @@
@model BlogPostTagListModel
@if (Model.Tags.Count > 0)
{
<div class="block block-popular-blogtags card">
<div class="card-header title">
<h4>@T("Blog.TagCloud")</h4>
</div>
<div class="listbox">
<ul class="list-group list-group-flush">
@foreach (var item in Model.Tags)
{
<li class="list-group-item">
<a href="@Url.RouteUrl("BlogByTag", new { tag = item.Name })" style="font-size:@(Model.GetFontSize(item))%;"><i class="fa fa-angle-double-right" aria-hidden="true"></i> @item.Name</a>
</li>
}
</ul>
</div>
</div>
}

View File

@ -0,0 +1,106 @@
@model BlogPostListModel
@using Nop.Core.Domain.Blogs
@{
Layout = "_ColumnsTwo";
//title
NopHtml.AddTitleParts(T("PageTitle.Blog").Text);
//page class
NopHtml.AppendPageCssClassParts("html-blog-page");
}
@section left {
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.LeftSideColumnBlogBefore, additionalData = Model })
@await Component.InvokeAsync(typeof(BlogMonthsViewComponent))
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.LeftSideColumnAfterBlogArchive, additionalData = Model })
@await Component.InvokeAsync(typeof(BlogTagsViewComponent))
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.LeftSideColumnBlogAfter, additionalData = Model })
}
<div class="page blog-page">
<div class="page-title">
<a href="@Url.RouteUrl("BlogRSS", new { languageId = Model.WorkingLanguageId })" class="link-rss" title="@T("Blog.RSS.Hint")"><i class="fa fa-rss-square" aria-hidden="true"></i></a>
<h1>
@if (string.IsNullOrEmpty(Model.PagingFilteringContext.Tag))
{
if (Model.PagingFilteringContext.GetParsedMonth().HasValue)
{
@string.Format(T("Blog.FilteredByMonth").Text, Model.PagingFilteringContext.GetParsedMonth().Value.Year, Model.PagingFilteringContext.GetParsedMonth().Value.ToString("MMMM"))
}
else
{
@T("Blog")
}
}
else
{
@string.Format(T("Blog.TaggedWith").Text, Model.PagingFilteringContext.Tag)
}
</h1>
</div>
<div class="page-body">
<div class="blog-posts row">
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BlogListPageBeforePosts, additionalData = Model })
@foreach (var item in Model.BlogPosts)
{
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BlogListPageBeforePost, additionalData = item })
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 mb-4">
<div class="blog-section">
<div class="post">
<div class="post-head">
<a class="post-title" href="@(Url.RouteUrl<BlogPost>(new { SeName = item.SeName }))">@item.Title</a>
<span class="post-date">@item.CreatedOn.ToString("D")</span>
</div>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BlogListPageBeforePostBody, additionalData = item })
<div class="post-body">
@Html.Raw(!string.IsNullOrEmpty(item.BodyOverview) ? item.BodyOverview : item.Body)
</div>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BlogListPageAfterPostBody, additionalData = item })
<div class="blog-details">
@if (item.Tags.Count > 0)
{
<div class="tags">
<label>@T("Blog.Tags"):</label>
<ul>
@for (var i = 0; i < item.Tags.Count; i++)
{
var tag = item.Tags[i];
<li><a href="@Url.RouteUrl("BlogByTag", new {tag = tag})">@tag</a></li>
if (i != item.Tags.Count - 1)
{
<li class="separator">,</li>
}
}
</ul>
</div>
}
<div class="buttons">
@if (item.AllowComments)
{
<a href="@(Url.RouteUrl<BlogPost>(new { SeName = item.SeName }, fragment: "comments"))" class="read-comments">@string.Format(T("Blog.CommentsLink").Text, item.NumberOfComments)</a>
}
<a href="@(Url.RouteUrl<BlogPost>(new { SeName = item.SeName }))" class="btn btn-primary read-more">@T("Blog.MoreInfo")</a>
</div>
</div>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BlogListPageInsidePost, additionalData = item })
</div>
</div>
</div>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BlogListPageAfterPost, additionalData = item })
}
</div>
@{
var pager = Html.Pager(Model.PagingFilteringContext).QueryParam("pagenumber");
}
@if (!(await pager.IsEmpty()))
{
<div class="pagination justify-content-center">
@pager
</div>
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BlogListPageAfterPosts, additionalData = Model })
</div>
</div>

View File

@ -0,0 +1,16 @@
@model ActiveDiscussionsModel
@{
Layout = "_ColumnsOne";
//title
NopHtml.AddTitleParts(T("Forum.PageTitle.ActiveDiscussions").Text);
//page class
NopHtml.AppendPageCssClassParts("html-active-discussions-page");
}
<div class="page active-discussions-page">
@await Component.InvokeAsync(typeof(ForumBreadcrumbViewComponent))
@await Html.PartialAsync("_ForumHeader")
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsActivediscussionsAfterHeader, additionalData = Model })
@await Html.PartialAsync("_ActiveTopics", Model)
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsActivediscussionsAfterTopics, additionalData = Model })
</div>

View File

@ -0,0 +1,2 @@
@model ActiveDiscussionsModel
@await Html.PartialAsync("_ActiveTopics", Model)

View File

@ -0,0 +1,44 @@
@model ForumBreadcrumbModel
@using Nop.Core.Domain.Common
@inject CommonSettings commonSettings
@{
var breadcrumbDelimiter = commonSettings.BreadcrumbDelimiter;
}
<div class="breadcrumb forum-breadcrumb">
<ul>
<li class="breadcrumb-item">
<a href="@Url.RouteUrl("Homepage")" title="@T("Forum.Breadcrumb.HomeTitle")">@T("Forum.Home")</a>
</li>
<li class="breadcrumb-item active">
<span class="delimiter">@breadcrumbDelimiter</span>
@Html.RouteLink(T("Forum.Forums").Text, "Boards", null, new { title = T("Forum.Breadcrumb.ForumHomeTitle") })
</li>
@if (Model.ForumGroupId > 0)
{
<li class="breadcrumb-item">
<span class="delimiter">@breadcrumbDelimiter</span>
@Html.RouteLink(Model.ForumGroupName, "ForumGroupSlug",
new { id = Model.ForumGroupId, slug = Model.ForumGroupSeName },
new { title = $"{T("Forum.Breadcrumb.ForumGroupTitle")}: {Model.ForumGroupName} " })
</li>
}
@if (Model.ForumId > 0)
{
<li class="breadcrumb-item">
<span class="delimiter">@breadcrumbDelimiter</span>
@Html.RouteLink(Model.ForumName, "ForumSlug",
new { id = Model.ForumId, slug = Model.ForumSeName },
new { title = $"{T("Forum.Breadcrumb.ForumTitle")}: {Model.ForumName} " })
</li>
}
@if (Model.ForumTopicId > 0)
{
<li class="breadcrumb-item">
<span class="delimiter">@breadcrumbDelimiter</span>
@Html.RouteLink(Model.ForumTopicSubject, "TopicSlug",
new { id = Model.ForumTopicId, slug = Model.ForumTopicSeName },
new { title = $"{T("Forum.Breadcrumb.TopicTitle")}: {Model.ForumTopicSubject} " })
</li>
}
</ul>
</div>

View File

@ -0,0 +1,33 @@
@model LastPostModel
@if (Model.Id > 0)
{
<div class="date">
@Model.PostCreatedOnStr
</div>
if (Model.ShowTopic)
{
<div class="origin">
<label>@T("Forum.In"):</label>
@Html.RouteLink(Model.ForumTopicSubject, "TopicSlug", new { id = Model.ForumTopicId, slug = Model.ForumTopicSeName })
</div>
}
<div class="author">
<label>@T("Forum.By"):</label>
@if (Model.AllowViewingProfiles)
{
@Html.RouteLink(Model.CustomerName, "CustomerProfile", new { Id = Model.CustomerId })
}
else
{
<span>@Model.CustomerName</span>
}
</div>
}
else
{
<div class="no-post">
<div class="alert alert-danger">
@T("Forum.NoPosts")
</div>
</div>
}

View File

@ -0,0 +1,111 @@
@model CustomerForumSubscriptionsModel
@{
Layout = "_ColumnsTwo";
//title
NopHtml.AddTitleParts(T("PageTitle.ForumSubscriptions").Text);
//page class
NopHtml.AppendPageCssClassParts("html-account-page");
NopHtml.AppendPageCssClassParts("html-forum-subscriptions-page");
}
@section left
{
@await Component.InvokeAsync(typeof(CustomerNavigationViewComponent),new { selectedTabId = CustomerNavigationEnum.ForumSubscriptions })
}
<div class="page account-page forum-subscriptions-page">
<div class="page-title">
<h1>@T("Account.MyAccount") - @T("Account.ForumSubscriptions")</h1>
</div>
<div class="page-body">
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.CustomerForumSubscriptionsTop, additionalData = Model })
@if (Model.ForumSubscriptions.Count > 0)
{
<div class="description alert alert-info">
@T("Account.ForumSubscriptions.Description")
</div>
<script asp-location="Footer">
$(function () {
$('#selectall').on('click', function () {
$('.subscription-list .rowcheckbox').prop('checked', $(this).is(':checked')).trigger('change');
});
$('.subscription-list .rowcheckbox').on('change', function (e) {
var numChkBoxes = $('.subscription-list .rowcheckbox').length;
var numChkBoxesChecked = $('.subscription-list .rowcheckbox:checked').length;
$('#selectall').prop('checked', numChkBoxes == numChkBoxesChecked && numChkBoxes > 0);
});
});
</script>
<form asp-route="CustomerForumSubscriptions" method="post">
<div class="subscription-list">
<div class="table-wrapper">
<table class="data-table table table-bordered table-hover">
<colgroup>
<col width="1" />
<col />
</colgroup>
<thead>
<tr>
<th class="select-boxes">
<div class="form-check m-0">
<input class="form-check-input" type="checkbox" id="selectall" />
<label for="selectall" class="form-check-label"></label>
</div>
</th>
<th class="info">
@T("Account.ForumSubscriptions.InfoColumn")
</th>
</tr>
</thead>
<tbody>
@for (var i = 0; i < Model.ForumSubscriptions.Count; i++)
{
var item = Model.ForumSubscriptions[i];
<tr @(i % 2 == 0 ? Html.Raw(" class=\"odd\"") : Html.Raw(" class=\"even\""))>
<td class="select-boxes">
<div class="form-check m-0">
<input class="rowcheckbox form-check-input" type="checkbox" name="fs@(item.Id)" id="fs@(item.Id)" />
<label class="form-check-label" for="fs@(item.Id)"></label>
</div>
</td>
<td class="info">
@if (item.TopicSubscription)
{
@Html.RouteLink(item.Title, "TopicSlug", new { Id = item.ForumTopicId, slug = item.Slug })
}
else
{
@Html.RouteLink(item.Title, "ForumSlug", new { Id = item.ForumId, slug = item.Slug })
}
</td>
</tr>
}
</tbody>
</table>
</div>
@{
var pager = await Html.PagerAsync(Model.PagerModel);
}
@if (!string.IsNullOrEmpty(await pager.RenderHtmlContentAsync()))
{
<div class="pagination justify-content-center">
@pager
</div>
}
<div class="buttons">
<button type="submit" class="btn btn-primary button-1 delete-selected-fs-button">@T("Account.ForumSubscriptions.DeleteSelected")</button>
</div>
</div>
</form>
}
else
{
<div class="no-data">
<div class="alert alert-danger">
@T("Account.ForumSubscriptions.NoSubscriptions")
</div>
</div>
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.CustomerForumSubscriptionsBottom, additionalData = Model })
</div>
</div>

View File

@ -0,0 +1,200 @@
@model ForumPageModel
@using Nop.Core.Domain.Forums
@using Nop.Services.Localization
@inject ILocalizationService localizationService
@{
Layout = "_ColumnsOne";
//title
NopHtml.AddTitleParts(Model.Name);
//page class
NopHtml.AppendPageCssClassParts("html-forum-page");
}
<div class="page forum-page">
@await Component.InvokeAsync(typeof(ForumBreadcrumbViewComponent), new { forumId = Model.Id })
@await Html.PartialAsync("_ForumHeader")
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsForumAfterHeader, additionalData = Model })
<nop-antiforgery-token />
<div class="forum-info">
<div class="forum-name">
@if (Model.ForumFeedsEnabled)
{
<a href="@Url.RouteUrl("ForumRSS", new { id = Model.Id })" class="link-rss" title="@T("Forum.ForumRSSLinkTitle")">@T("Forum.RSS")</a>
}
<h1>@Model.Name</h1>
</div>
<div class="forum-description alert alert-info">
<p>@Model.Description</p>
</div>
</div>
<div class="forum-actions">
<div class="actions">
@Html.RouteLink(T("Forum.NewTopic").ToString(), "TopicCreate", new { id = Model.Id }, new { @class = "new-topic" })
@if (Model.IsCustomerAllowedToSubscribe)
{
<a class="watch-forum btn btn-secondary" href="#" id="watch-forum">@Model.WatchForumText</a>
<script asp-location="Footer">
$(function () {
$('#watch-forum').on('click', function () {
var postData = {};
addAntiForgeryToken(postData);
$.ajax({
cache: false,
type: "POST",
url: "@Url.RouteUrl("ForumWatch", new {id = Model.Id})",
data: postData,
dataType: "json",
success: function (data, textStatus, jqXHR) {
$('#watch-forum').text(data.Text);
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Failed to watch');
}
});
});
});
</script>
}
</div>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsForumTop, additionalData = Model })
@{
var pager = await Html.PagerAsync(new PagerModel(localizationService)
{
PageSize = Model.TopicPageSize,
TotalRecords = Model.TopicTotalRecords,
PageIndex = Model.TopicPageIndex,
ShowTotalSummary = false,
RouteActionName = "ForumSlugPaged",
UseRouteLinks = true,
RouteValues = new SlugRouteValues { Id = Model.Id, Slug = Model.SeName }
});
}
@if (!string.IsNullOrEmpty(await pager.RenderHtmlContentAsync()))
{
<div class="pagination justify-content-center upper">
@pager
</div>
}
</div>
<div class="forums-table-section topic-group">
@if (Model.ForumTopics.Count > 0)
{
<div class="table-wrapper">
<table class="forum-table table table-bordered table-hover">
<colgroup>
<col width="1" />
<col />
<col width="1" />
@if (Model.AllowPostVoting)
{
<col width="1" />
}
<col width="1" />
</colgroup>
<thead>
<tr>
<th class="topic-details" colspan="2">
@T("Forum.TopicTitle")
</th>
<th class="replies">
@T("Forum.Replies")
</th>
<th class="views">
@T("Forum.Views")
</th>
@if (Model.AllowPostVoting)
{
<th class="votes">
@T("Forum.Votes")
</th>
}
<th class="latest-post">
@T("Forum.LatestPost")
</th>
</tr>
</thead>
<tbody>
@foreach (var topic in @Model.ForumTopics)
{
var topicType = "post";
var topicText = string.Empty;
switch (topic.ForumTopicType)
{
case ForumTopicType.Normal:
topicType = "post";
break;
case ForumTopicType.Sticky:
topicType = "sticky";
topicText = $"[{T("Forum.Sticky")}]";
break;
case ForumTopicType.Announcement:
topicType = "announcement";
topicText = $"[{T("Forum.Announcement")}]";
break;
default:
topicType = "post";
break;
}
<tr>
<td class="image">
<div class="@topicType"></div>
</td>
<td class="topic-details">
<div class="topic-title">
@Html.RouteLink(topic.Subject, "TopicSlug", new { id = topic.Id, slug = topic.SeName })
@if (!string.IsNullOrEmpty(topicText))
{
<span class="topic-type">@topicText</span>
}
</div>
@if (topic.NumPosts > Model.PostsPageSize)
{
<div class="topic-pager">
@await Html.ForumTopicSmallPagerAsync(topic)
</div>
}
<div class="topic-starter">
@if (topic.CustomerId > 0)
{
<label>@T("Forum.Author"):</label>
if (topic.AllowViewingProfiles)
{
@Html.RouteLink(topic.CustomerName, "CustomerProfile", new { Id = topic.CustomerId })
}
else
{
@topic.CustomerName
}
}
</div>
</td>
<td class="replies">
@topic.NumReplies
</td>
<td class="views">
@topic.Views
</td>
@if (Model.AllowPostVoting)
{
<td class="votes">
@topic.Votes
</td>
}
<td class="latest-post">
@await Component.InvokeAsync(typeof(ForumLastPostViewComponent), new { forumPostId = topic.LastPostId, showTopic = false })
</td>
</tr>
}
</tbody>
</table>
</div>
}
</div>
@if (!string.IsNullOrEmpty(await pager.RenderHtmlContentAsync()))
{
<div class="pagination justify-content-center lower">
@pager
</div>
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsForumBottom, additionalData = Model })
</div>

View File

@ -0,0 +1,16 @@
@model ForumGroupModel
@{
Layout = "_ColumnsOne";
//title
NopHtml.AddTitleParts(Model.Name);
//page class
NopHtml.AppendPageCssClassParts("html-forum-group-page");
}
<div class="page forum-group-page">
@await Component.InvokeAsync(typeof(ForumBreadcrumbViewComponent), new { forumGroupId = Model.Id })
@await Html.PartialAsync("_ForumHeader")
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsForumGroupAfterHeader, additionalData = Model })
@await Html.PartialAsync("_ForumGroup", Model)
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsForumGroupBottom, additionalData = Model })
</div>

View File

@ -0,0 +1,21 @@
@model BoardsIndexModel
@{
Layout = "_ColumnsOne";
//title
NopHtml.AddTitleParts(T("Forum.PageTitle.Default").Text);
//page class
NopHtml.AppendPageCssClassParts("html-forums-main-page");
}
<div class="page forums-main-page">
@await Component.InvokeAsync(typeof(TopicBlockViewComponent), new { systemName = "ForumWelcomeMessage" })
@await Html.PartialAsync("_ForumHeader")
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsMainAfterHeader, additionalData = Model })
@foreach (var forumGroup in Model.ForumGroups)
{
await Html.RenderPartialAsync("_ForumGroup", forumGroup);
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsMainBeforeActivediscussions, additionalData = Model })
@await Component.InvokeAsync(typeof(ForumActiveDiscussionsSmallViewComponent))
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsMainAfterActivediscussions, additionalData = Model })
</div>

View File

@ -0,0 +1,11 @@
@model EditForumPostModel
@{
Layout = "_ColumnsOne";
NopHtml.AddTitleParts(T("Forum.PageTitle.PostNew").Text);
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsPostCreateBefore, additionalData = Model })
<form asp-route="PostCreate" method="post">
@await Html.PartialAsync("_CreateUpdatePost", Model)
</form>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsPostCreateAfter, additionalData = Model })

View File

@ -0,0 +1,11 @@
@model EditForumPostModel
@{
Layout = "_ColumnsOne";
NopHtml.AddTitleParts(T("Forum.PageTitle.PostEdit").Text);
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsPostEditBefore, additionalData = Model })
<form asp-route="PostEdit" method="post">
@await Html.PartialAsync("_CreateUpdatePost", Model)
</form>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsPostEditAfter, additionalData = Model })

View File

@ -0,0 +1,256 @@
@model Nop.Web.Models.Boards.SearchModel
@using Nop.Core.Domain.Forums
@using Nop.Services.Localization
@using Nop.Web.Factories
@using Nop.Web.Framework.TagHelpers.Shared
@using Microsoft.AspNetCore.Mvc.TagHelpers
@inject ILocalizationService localizationService
@{
Layout = "_ColumnsOne";
//title
NopHtml.AddTitleParts(T("Forum.PageTitle.Search").Text);
//page class
NopHtml.AppendPageCssClassParts("html-forum-search-page");
}
<script asp-location="Footer">
$(function () {
toggleAdvancedSearch();
$('#advs').on('click', function () {
toggleAdvancedSearch();
});
});
function toggleAdvancedSearch() {
if ($('#advs').is(':checked')) {
$('#advanced-search').show();
}
else {
$('#advanced-search').hide();
}
}
</script>
@await Component.InvokeAsync(typeof(ForumBreadcrumbViewComponent))
<div class="page forum-search-page">
<div class="page-title">
<h1>@T("Forum.Search")</h1>
</div>
<div class="page-body">
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsSearchBeforeSearchform, additionalData = Model })
<div class="search-input">
<form asp-route="Search" method="get">
<div class="fieldset">
<div class="form-fields">
<div class="basic-search">
<div class="row mb-3">
<label class="col-form-label col-sm-4 col-md-4 col-lg-4 col-xl-4 pb-0">@T("Forum.Search.SearchKeyword")</label>
<div class="col-sm-8 col-md-5 col-lg-5 col-xl-5">
<input type="text" name="searchterms" id="searchterms" class="forum-search-text form-control" value="@Model.SearchTerms" />
</div>
</div>
<div class="row mb-3">
<div class="offset-sm-4 offset-md-4 offset-lg-4 offset-xl-4 col-sm-10 col-md-10">
<div class="form-check mb-2 mr-sm-2 mb-sm-0">
<input @(Model.ShowAdvancedSearch ? "checked=\"checked\"" : "") id="advs" name="advs" type="checkbox" value="true" class="form-check-input">
<label for="advs" class="form-check-label">@T("Forum.Search.AdvancedSearch")</label>
</div>
</div>
</div>
</div>
<div class="advanced-search" id="advanced-search" style="display: none;">
<div class="row mb-3">
<label class="col-form-label col-sm-4 col-md-4 col-lg-4 col-xl-4">@T("Forum.Search.SearchInForum")</label>
<div class="col-sm-8 col-md-5 col-lg-5 col-xl-5">
<select name="forumId" id="forumId" asp-items="@(new SelectList(Model.ForumList, "Value", "Text", Model.ForumIdSelected))" class="form-control custom-select"></select>
</div>
</div>
<div class="row mb-3">
<label class="col-form-label col-sm-4 col-md-4 col-lg-4 col-xl-4">@T("Forum.Search.SearchWithin")</label>
<div class="col-sm-8 col-md-5 col-lg-5 col-xl-5">
<select name="within" id="within" asp-items="@(new SelectList(Model.WithinList, "Value", "Text", Model.WithinSelected))" class="form-control custom-select"></select>
</div>
</div>
<div class="row mb-3">
<label class="col-form-label col-sm-4 col-md-4 col-lg-4 col-xl-4">@T("Forum.Search.LimitResultsToPrevious")</label>
<div class="col-sm-8 col-md-5 col-lg-5 col-xl-5">
<select name="limitDays" id="limitDays" asp-items="@(new SelectList(Model.LimitList, "Value", "Text", Model.LimitDaysSelected))" class="form-control custom-select"></select>
</div>
</div>
</div>
</div>
</div>
<div class="row mb-3">
<div class="offset-sm-4 offset-md-4 offset-lg-4 offset-xl-4 col-sm-12 col-md-8 col-lg-8 col-xl-8">
<div class="buttons">
<button type="submit" class="btn btn-primary button-1 forum-search-button">@T("Forum.SearchButton")</button>
</div>
</div>
</div>
</form>
</div>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsSearchAfterSearchform, additionalData = Model })
<div class="search-error">
@Model.Error
</div>
<div class="search-results">
@{
var searchterms = Model.SearchTerms;
string advs = null;
string within = null;
string limitDays = null;
string forumId = null;
if (Model.ShowAdvancedSearch)
{
advs = "true";
within = Model.WithinSelected.ToString();
limitDays = Model.LimitDaysSelected.ToString();
forumId = Model.ForumIdSelected.ToString();
}
var pager = await Html.PagerAsync(new PagerModel(localizationService)
{
PageSize = Model.TopicPageSize,
TotalRecords = Model.TopicTotalRecords,
PageIndex = Model.TopicPageIndex,
ShowTotalSummary = false,
RouteActionName = "Search",
RouteValues = new ForumModelFactory.ForumSearchRouteValues { Advs = advs, Searchterms = searchterms, ForumId = forumId, Within = within, LimitDays = limitDays },
});
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsSearchBeforeResults, additionalData = Model })
@if (!string.IsNullOrEmpty(await pager.RenderHtmlContentAsync()))
{
<div class="pagination justify-content-center upper">
@pager
</div>
}
@if (Model.NoResultsVisisble)
{
<div class="no-result alert alert-danger">
@T("Forum.SearchNoResultsText")
</div>
}
<div class="forums-table-section topic-group">
@if (Model.SearchResultsVisible)
{
<div class="table-wrapper">
<table class="forum-table table table-bordered table-hover">
<colgroup>
<col width="1" />
<col />
<col width="1" />
@if (Model.AllowPostVoting)
{
<col width="1" />
}
<col width="1" />
</colgroup>
<thead>
<tr>
<th class="topic-details" colspan="2">
@T("Forum.TopicTitle")
</th>
<th class="replies">
@T("Forum.Replies")
</th>
<th class="views">
@T("Forum.Views")
</th>
@if (Model.AllowPostVoting)
{
<th class="votes">
@T("Forum.Votes")
</th>
}
<th class="latest-post">
@T("Forum.LatestPost")
</th>
</tr>
</thead>
<tbody>
@foreach (var topic in @Model.ForumTopics)
{
var topicType = "post";
var topicText = string.Empty;
switch (topic.ForumTopicType)
{
case ForumTopicType.Normal:
topicType = "post";
break;
case ForumTopicType.Sticky:
topicType = "sticky";
topicText = $"[{T("Forum.Sticky")}]";
break;
case ForumTopicType.Announcement:
topicType = "announcement";
topicText = $"[{T("Forum.Announcement")}]";
break;
default:
topicType = "post";
break;
}
<tr>
<td class="image">
<div class="@topicType"></div>
</td>
<td class="topic-details">
<div class="topic-title">
@Html.RouteLink(topic.Subject, "TopicSlug", new { id = topic.Id, slug = topic.SeName })
@if (!string.IsNullOrEmpty(topicText))
{
<span class="topic-type">@topicText</span>
}
</div>
@if (topic.NumPosts > Model.PostsPageSize)
{
<div class="topic-pager">
@await Html.ForumTopicSmallPagerAsync(topic)
</div>
}
<div class="topic-starter">
@if (topic.CustomerId > 0)
{
<label>@T("Forum.Author"):</label>
if (topic.AllowViewingProfiles)
{
@Html.RouteLink(topic.CustomerName, "CustomerProfile", new { Id = topic.CustomerId })
}
else
{
@topic.CustomerName
}
}
</div>
</td>
<td class="replies">
@topic.NumReplies
</td>
<td class="views">
@topic.Views
</td>
@if (Model.AllowPostVoting)
{
<td class="votes">
@topic.Votes
</td>
}
<td class="latest-post">
@await Component.InvokeAsync(typeof(ForumLastPostViewComponent), new { forumPostId = topic.LastPostId, showTopic = false })
</td>
</tr>
}
</tbody>
</table>
</div>
}
</div>
@if (!string.IsNullOrEmpty(await pager.RenderHtmlContentAsync()))
{
<div class="pagination justify-content-center lower">
@pager
</div>
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsSearchAfterResults, additionalData = Model })
</div>
</div>
</div>

View File

@ -0,0 +1,176 @@
@using Nop.Services.Localization
@model ForumTopicPageModel
@inject ILocalizationService localizationService
@{
Layout = "_ColumnsOne";
//title
NopHtml.AddTitleParts(Model.Subject);
//page class
NopHtml.AppendPageCssClassParts("html-forum-topic-page");
}
<div class="page forum-topic-page">
@await Component.InvokeAsync(typeof(ForumBreadcrumbViewComponent), new { forumTopicId = Model.Id })
@await Html.PartialAsync("_ForumHeader")
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsTopicAfterHeader, additionalData = Model })
<div class="topic-name">
<h1>@Model.Subject</h1>
</div>
<div class="topic-actions upper">
<div class="actions">
@if (Model.IsCustomerAllowedToEditTopic)
{
@Html.RouteLink(T("Forum.EditTopic").Text, "TopicEdit", new { id = Model.Id }, new { @class = "edit-topic-button" })
}
@if (Model.IsCustomerAllowedToDeleteTopic)
{
<a href="#" class="delete-topic-button" onclick="return deletetopic(@(Model.Id))">@T("Forum.DeleteTopic").Text</a>
<script asp-location="Footer">
function deletetopic(topicId) {
if (confirm('@T("Common.AreYouSure")')) {
var postData = {
id: topicId
};
addAntiForgeryToken(postData);
$.ajax({
cache: false,
type: "POST",
url: "@Url.RouteUrl("TopicDelete")",
data: postData,
dataType: "json",
success: function (data, textStatus, jqXHR) {
location.href = data.redirect;
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Failed to delete');
}
});
}
return false;
}
</script>
}
@if (Model.IsCustomerAllowedToMoveTopic)
{
@Html.RouteLink(T("Forum.MoveTopic").Text, "TopicMove", new { id = Model.Id }, new { @class = "move-topic-button" })
}
@Html.RouteLink(T("Forum.Reply").Text, "PostCreate", new { id = Model.Id }, new { @class = "reply-topic-button" })
@if (Model.IsCustomerAllowedToSubscribe)
{
<a class="watch-topic-button" href="#" id="watch-topic-top">@Model.WatchTopicText</a>
<script asp-location="Footer">
$(function () {
$('#watch-topic-top').on('click', function () {
var postData = {};
addAntiForgeryToken(postData);
$.ajax({
cache: false,
type: "POST",
data: postData,
url: "@Url.RouteUrl("TopicWatch", new { id = Model.Id })",
dataType: "json",
success: function (data, textStatus, jqXHR) {
$('#watch-topic-top').text(data.Text);
$('#watch-topic-bottom').text(data.Text);
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Failed to watch');
}
});
});
});
</script>
}
</div>
@{
var pager = await Html.PagerAsync(new PagerModel(localizationService)
{
PageSize = Model.PostsPageSize,
TotalRecords = Model.PostsTotalRecords,
PageIndex = Model.PostsPageIndex,
ShowTotalSummary = false,
RouteActionName = "TopicSlugPaged",
UseRouteLinks = true,
RouteValues = new SlugRouteValues { Id = Model.Id, Slug = Model.SeName }
});
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsTopicTop, additionalData = Model })
@if (!string.IsNullOrEmpty(await pager.RenderHtmlContentAsync()))
{
<div class="pagination justify-content-center upper">
@pager
</div>
}
</div>
<div class="topic-posts">
@foreach (var post in @Model.ForumPostModels)
{
await Html.RenderPartialAsync("_ForumPost", post);
}
</div>
<div class="topic-actions lower">
<div class="actions">
@Html.RouteLink(T("Forum.Reply").Text, "PostCreate", new { id = Model.Id }, new { @class = "reply-topic-button" })
@if (Model.IsCustomerAllowedToSubscribe)
{
<a class="watch-topic-button" href="#" id="watch-topic-bottom">@Model.WatchTopicText</a>
<script asp-location="Footer">
$(function () {
$('#watch-topic-bottom').on('click', function() {
var postData = {};
addAntiForgeryToken(postData);
$.ajax({
cache: false,
type: "POST",
url: "@Url.RouteUrl("TopicWatch", new {id = Model.Id})",
data: postData,
dataType: "json",
success: function (data, textStatus, jqXHR) {
$('#watch-topic-top').text(data.Text);
$('#watch-topic-bottom').text(data.Text);
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Failed to watch');
}
});
});
});
</script>
}
</div>
@if (!string.IsNullOrEmpty(await pager.RenderHtmlContentAsync()))
{
<div class="pagination justify-content-center lower">
@pager
</div>
}
</div>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsTopicBottom, additionalData = Model })
</div>
<script asp-location="Footer">
function deletepost(postId) {
if (confirm('@T("Common.AreYouSure")')) {
var postData = {
id: postId
};
addAntiForgeryToken(postData);
$.ajax({
cache: false,
type: "POST",
url: "@Url.RouteUrl("PostDelete")",
data: postData,
dataType: "json",
success: function (data, textStatus, jqXHR) {
location.href = data.redirect;
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Failed to delete');
}
});
}
return false;
}
</script>

View File

@ -0,0 +1,11 @@
@model EditForumTopicModel
@{
Layout = "_ColumnsOne";
NopHtml.AddTitleParts(T("Forum.PageTitle.TopicNew").Text);
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsTopicCreateBefore, additionalData = Model })
<form asp-route="TopicCreate" method="post">
@await Html.PartialAsync("_CreateUpdateTopic", Model)
</form>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsTopicCreateAfter, additionalData = Model })

View File

@ -0,0 +1,11 @@
@model EditForumTopicModel
@{
Layout = "_ColumnsOne";
NopHtml.AddTitleParts(T("Forum.PageTitle.TopicEdit").Text);
}
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsTopicEditBefore, additionalData = Model })
<form asp-route="TopicEdit" method="post">
@await Html.PartialAsync("_CreateUpdateTopic", Model)
</form>
@await Component.InvokeAsync(typeof(WidgetViewComponent), new { widgetZone = PublicWidgetZones.BoardsTopicEditAfter, additionalData = Model })

View File

@ -0,0 +1,38 @@
@model TopicMoveModel
@{
Layout = "_ColumnsOne";
//title
NopHtml.AddTitleParts(T("Forum.PageTitle.MoveTopic").Text);
//page class
NopHtml.AppendPageCssClassParts("html-move-topic-page");
}
@await Component.InvokeAsync(typeof(ForumBreadcrumbViewComponent), new { forumTopicId = Model.Id })
<div class="page move-topic-page">
<div class="page-title">
<h1>@T("Forum.MoveTopic")</h1>
</div>
<div class="page-body">
<form asp-route="TopicMove" method="post">
<input type="hidden" asp-for="Id" />
<div class="fieldset">
<div class="form-fields">
<div class="row mb-3">
<label class="col-sm-12 col-md-4 col-lg-4 col-xl-4 col-form-label pl-0 pr-0 pt-0">@T("Forum.SelectTheForumToMoveTopic"):</label>
<div class="col-sm-12 col-md-5 col-lg-5 col-xl-5">
<select asp-for="ForumSelected" asp-items="@(new SelectList(Model.ForumList, "Value", "Text"))" class="forum-topic-title-text form-control custom-select"></select>
</div>
</div>
</div>
</div>
<div class="row mb-3">
<div class="offset-md-4 offset-lg-4 offset-xl-4 col-sm-12 col-md-8 col-lg-8 col-xl-8">
<div class="buttons">
<button type="submit" class="btn btn-primary button-1 submit-forum-topic-button">@T("Forum.Submit")</button>
<button type="button" class="btn btn-primary button-2 cancel-forum-topic-button" onclick="setLocation('@Url.RouteUrl("TopicSlug", new { id = Model.Id, slug = Model.TopicSeName })')">@T("Forum.Cancel")</button>
</div>
</div>
</div>
</form>
</div>
</div>

View File

@ -0,0 +1,131 @@
@using Nop.Services.Localization
@using Nop.Web.Factories
@model ActiveDiscussionsModel
@inject ILocalizationService localizationService
<div class="forums-table-section topic-group active-discussions">
<div class="forums-table-section-title">
@if (Model.ActiveDiscussionsFeedEnabled)
{
<a href="@Url.RouteUrl("ActiveDiscussionsRSS")" class="link-rss" title="@T("Forum.ActiveDiscussionsRSSLinkTitle")"><i class="fa fa-rss-square" aria-hidden="true"></i> @T("Forum.RSS")</a>
}
<strong>@T("Forum.ActiveDiscussions")</strong>
</div>
@{
var pager = await Html.PagerAsync(new PagerModel(localizationService)
{
PageSize = Model.TopicPageSize,
TotalRecords = Model.TopicTotalRecords,
PageIndex = Model.TopicPageIndex,
ShowTotalSummary = false,
RouteActionName = "ActiveDiscussionsPaged",
UseRouteLinks = true,
RouteValues = new ForumModelFactory.ForumActiveDiscussionsRouteValues()
});
}
@if (!string.IsNullOrEmpty(await pager.RenderHtmlContentAsync()))
{
<div class="pagination justify-content-center upper">
@pager
</div>
}
<div class="forums-table-section-body">
@if (Model.ForumTopics.Count > 0)
{
<div class="table-wrapper">
<table class="forum-table table table-bordered table-hover">
<colgroup>
<col />
<col width="1" />
<col width="1" />
@if (Model.AllowPostVoting)
{
<col width="1" />
}
<col width="1" />
</colgroup>
<thead>
<tr>
<th class="topic-details">
@T("Forum.TopicTitle")
</th>
<th class="replies">
@T("Forum.Replies")
</th>
<th class="views">
@T("Forum.Views")
</th>
@if (Model.AllowPostVoting)
{
<th class="votes">
@T("Forum.Votes")
</th>
}
<th class="latest-post">
@T("Forum.LatestPost")
</th>
</tr>
</thead>
<tbody>
@foreach (var topic in Model.ForumTopics)
{
<tr>
<td class="topic-details">
<div class="topic-title">
@Html.RouteLink(topic.Subject, "TopicSlug", new { id = topic.Id, slug = topic.SeName })
</div>
@if (topic.NumPosts > Model.PostsPageSize)
{
<div class="topic-pager">
@await Html.ForumTopicSmallPagerAsync(topic)
</div>
}
<div class="topic-starter">
@if (topic.CustomerId > 0)
{
<label>@T("Forum.Author"):</label>
if (topic.AllowViewingProfiles)
{
@Html.RouteLink(topic.CustomerName, "CustomerProfile", new { Id = topic.CustomerId })
}
else
{
@topic.CustomerName
}
}
</div>
</td>
<td class="replies">
@topic.NumReplies
</td>
<td class="views">
@topic.Views
</td>
@if (Model.AllowPostVoting)
{
<td class="votes">
@topic.Votes
</td>
}
<td class="latest-post">
@await Component.InvokeAsync(typeof(ForumLastPostViewComponent), new { forumPostId = topic.LastPostId, showTopic = false })
</td>
</tr>
}
</tbody>
</table>
</div>
}
</div>
@if (!string.IsNullOrEmpty(await pager.RenderHtmlContentAsync()))
{
<div class="pagination justify-content-center lower">
@pager
</div>
}
@if (Model.ViewAllLinkEnabled)
{
<div class="view-all">
@Html.RouteLink(T("Forum.ActiveDiscussions.ViewAll").Text, "ActiveDiscussions", null)
</div>
}
</div>

View File

@ -0,0 +1,78 @@
@model EditForumPostModel
@using Nop.Core.Domain.Forums;
@{
//page class
NopHtml.AppendPageCssClassParts("html-forum-edit-page");
}
@await Component.InvokeAsync(typeof(ForumBreadcrumbViewComponent), new { forumTopicId = Model.ForumTopicId })
<div class="page forum-edit-page">
<div class="page-title">
@if (Model.IsEdit)
{
<h1>@T("Forum.EditPost")</h1>
}
else
{
<h1>@T("Forum.NewPost")</h1>
}
</div>
<div class="page-body">
<div asp-validation-summary="ModelOnly" class="message-error alert alert-danger"></div>
<input type="hidden" asp-for="Id" />
<input type="hidden" asp-for="ForumTopicId" />
<div class="fieldset">
<div class="form-fields">
<div class="row mb-3">
<label class="col-sm-12 col-md-4 col-lg-4 col-xl-4 col-form-label pl-0 pr-0 pt-0">@T("Forum.ForumName"):</label>
<div class="col-sm-12 col-md-5 col-lg-5 col-xl-5">
<strong class="forum-subject">@Model.ForumName</strong>
</div>
</div>
<div class="row mb-3">
<label class="col-sm-12 col-md-4 col-lg-4 col-xl-4 col-form-label pl-0 pr-0 pt-0">@T("Forum.TopicTitle"):</label>
<div class="col-sm-12 col-md-5 col-lg-5 col-xl-5">
<strong class="forum-subject">@Model.ForumTopicSubject</strong>
</div>
</div>
<div class="row mb-3">
<label class="col-sm-12 col-md-4 col-lg-4 col-xl-4 col-form-label pl-0 pr-0 pt-0"></label>
<div class="col-sm-12 col-md-5 col-lg-5 col-xl-5">
@if (Model.ForumEditor == EditorType.BBCodeEditor)
{
<nop-bb-code-editor asp-for="Text" />
}
<textarea asp-for="Text" class="forum-post-text form-control"></textarea>
</div>
<div class="col-sm-12 col-md-3 col-lg-3 col-xl-3">
<span asp-validation-for="Text"></span>
</div>
</div>
@if (Model.IsCustomerAllowedToSubscribe)
{
<div class="row mb-3 mb-0">
<label class="col-sm-12 col-md-4 col-lg-4 col-xl-4 col-form-label pl-0 pr-0"></label>
<div class="col-sm-12 col-md-5 col-lg-5 col-xl-5">
<div class="form-check">
<input asp-for="Subscribed" class="form-check-input" />
<label asp-for="Subscribed" class="form-check-label">@T("Forum.NotifyWhenSomeonePostsInThisTopic")</label>
</div>
</div>
</div>
}
@if (Model.DisplayCaptcha)
{
<nop-captcha />
}
</div>
</div>
<div class="row mb-3">
<div class="offset-md-4 offset-lg-4 offset-xl-4 col-sm-12 col-md-8 col-lg-8 col-xl-8">
<div class="buttons">
<button type="submit" class="btn btn-primary button-1 submit-post-button">@T("Forum.Submit")</button>
<button type="button" class="btn btn-primary button-2 cancel-post-button" onclick="setLocation('@Url.RouteUrl("TopicSlug", new { id = Model.ForumTopicId, slug = Model.ForumTopicSeName })')">@T("Forum.Cancel")</button>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,90 @@
@model EditForumTopicModel
@using Nop.Core.Domain.Forums;
@{
//page class
NopHtml.AppendPageCssClassParts("html-forum-edit-page");
}
@await Component.InvokeAsync(typeof(ForumBreadcrumbViewComponent), new { forumId = Model.ForumId, forumTopicId = Model.Id })
<div class="page forum-edit-page">
<div class="page-title">
@if (Model.IsEdit)
{
<h1>@T("Forum.EditTopic")</h1>
}
else
{
<h1>@T("Forum.NewTopic")</h1>
}
</div>
<div class="page-body">
<div asp-validation-summary="ModelOnly" class="message-error alert alert-danger"></div>
<input type="hidden" asp-for="Id" />
<input type="hidden" asp-for="ForumId" />
<div class="fieldset">
<div class="form-fields">
<div class="row mb-3">
<label class="col-sm-12 col-md-4 col-lg-4 col-xl-4 col-form-label pl-0 pr-0 pt-0">@T("Forum.ForumName"):</label>
<div class="col-sm-12 col-md-5 col-lg-5 col-xl-5">
<strong class="forum-subject">@Model.ForumName</strong>
</div>
</div>
<div class="row mb-3">
<label class="col-sm-12 col-md-4 col-lg-4 col-xl-4 col-form-label pl-0 pr-0 pt-0">@T("Forum.TopicTitle"):</label>
<div class="col-sm-12 col-md-5 col-lg-5 col-xl-5">
<input asp-for="Subject" class="forum-topic-title-text form-control" />
</div>
<div class="col-sm-12 col-md-3 col-lg-3 col-xl-3">
<span asp-validation-for="Subject"></span>
</div>
</div>
<div class="row mb-3">
<label class="col-sm-12 col-md-4 col-lg-4 col-xl-4 col-form-label pl-0 pr-0 pt-0"></label>
<div class="col-sm-12 col-md-5 col-lg-5 col-xl-5">
@if (Model.ForumEditor == EditorType.BBCodeEditor)
{
<nop-bb-code-editor asp-for="Text" />
}
<textarea asp-for="Text" class="forum-post-text form-control"></textarea>
</div>
<div class="col-sm-12 col-md-3 col-lg-3 col-xl-3">
<span asp-validation-for="Text"></span>
</div>
</div>
@if (Model.IsCustomerAllowedToSetTopicPriority)
{
<div class="row mb-3">
<label class="col-sm-12 col-md-4 col-lg-4 col-xl-4 col-form-label pl-0 pr-0">@T("Forum.Priority"):</label>
<div class="col-sm-12 col-md-5 col-lg-5 col-xl-5">
<select asp-for="TopicTypeId" asp-items="@(new SelectList(Model.TopicPriorities, "Value", "Text", Model.TopicTypeId))" class="form-control custom-select"></select>
</div>
</div>
}
@if (Model.IsCustomerAllowedToSubscribe)
{
<div class="row mb-3 mb-0">
<label class="col-sm-12 col-md-4 col-lg-4 col-xl-4 col-form-label pl-0 pr-0"></label>
<div class="col-sm-12 col-md-5 col-lg-5 col-xl-5">
<div class="form-check">
<input asp-for="Subscribed" class="form-check-input" />
<label class="form-check-label" asp-for="Subscribed">@T("Forum.NotifyWhenSomeonePostsInThisTopic")</label>
</div>
</div>
</div>
}
@if (Model.DisplayCaptcha)
{
<nop-captcha />
}
</div>
</div>
<div class="row mb-3">
<div class="offset-md-4 offset-lg-4 offset-xl-4 col-sm-12 col-md-8 col-lg-8 col-xl-8">
<div class="buttons">
<button type="submit" class="btn btn-primary button-1 submit-topic-button">@T("Forum.Submit")</button>
<button type="button" class="btn btn-primary button-2 cancel-topic-button" onclick="setLocation('@Url.RouteUrl("ForumSlug", new { id = Model.ForumId, slug = Model.ForumSeName })')">@T("Forum.Cancel")</button>
</div>
</div>
</div>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More