Read More Button

2 weeks ago
Hi All i'm needing some help with a read more button.

I have copied the code from here https://www.nopcommerce.com/en/boards/topic/98063/read-more-option-on-the-category-page and I posted on there also but had no response.

I can get the button to display - act like its active but when clicking the button the text doesnt drop down. I assume its a conflict between cypherclean and the code or something dumb i have done.. but i'm struggling with my limited skill level.

Anyone want to point me in the right direction? I can beleive this isnt  standard part of nop or a plugin!

example page here https://fullworksfiresafety.com.au/fire-extinguishers-dry-powder

code from CategoryTemplate.ProductsInGridOrLines.cshtml in the theme folder

@model CategoryModel
@using Nop.Core.Domain.Common
@using Nop.Core.Domain.Seo
@inject Nop.Core.IWebHelper webHelper
@inject SeoSettings seoSettings
@inject CommonSettings commonSettings
@{
    Layout = "_ColumnsTwo";

    //title
    Html.AddTitleParts(!string.IsNullOrEmpty(Model.MetaTitle) ? Model.MetaTitle : Model.Name);
    //meta
    Html.AddMetaDescriptionParts(Model.MetaDescription);
    Html.AddMetaKeywordParts(Model.MetaKeywords);
    //page class
    Html.AppendPageCssClassParts("html-category-page");

    if (seoSettings.CanonicalUrlsEnabled)
    {
        var categoryUrl = Url.RouteUrl("Category", new { SeName = Model.SeName }, webHelper.GetCurrentRequestProtocol()).ToLowerInvariant();
        Html.AddCanonicalUrlParts(categoryUrl, seoSettings.QueryStringInCanonicalUrlsEnabled);
    }

    var breadcrumbDelimiter = commonSettings.BreadcrumbDelimiter;
}
@*category breadcrumb*@
@section Breadcrumb
{
    @if (Model.DisplayCategoryBreadcrumb)
    {
        <div class="breadcrumb">
            <ul itemscope itemtype="http://schema.org/BreadcrumbList">
                <li>
                    <a href="@Url.RouteUrl("Homepage")" title="@T("Categories.Breadcrumb.Top")">@T("Categories.Breadcrumb.Top")</a>
                    <span class="delimiter">@breadcrumbDelimiter</span>
                </li>
                @{ int position = 1; }
                @foreach (var cat in Model.CategoryBreadcrumb)
                {
                    var isLastCategory = cat.Id == Model.Id;
                    <li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">
                        @if (isLastCategory)
                        {
                            <strong class="current-item" itemprop="name">@cat.Name</strong>
                            <span itemprop="item" itemscope itemtype="http://schema.org/Thing"
                                  id="@Url.RouteUrl("Category", new {SeName = cat.SeName})">
                            </span>
                        }
                        else
                        {
                            <a href="@Url.RouteUrl("Category", new { SeName = cat.SeName })" title="@cat.Name" itemprop="item">
                                <span itemprop="name">@cat.Name</span>
                            </a>
                            <span class="delimiter">@breadcrumbDelimiter</span>
                        }
                        <meta itemprop="position" content="@position" />
                    </li>
                    position++;
                }
            </ul>
        </div>
        @await Component.InvokeAsync("Widget", new { widgetZone = PublicWidgetZones.CategoryDetailsAfterBreadcrumb, additionalData = Model })
    }
}

@section CatalogFilters {
    @await Component.InvokeAsync("Widget", new { widgetZone = PublicWidgetZones.CategoryDetailsBeforeFilters, additionalData = Model })
    @await Html.PartialAsync("_CatalogFilters", Model.CatalogProductsModel)
}
<style>
     .text {
        overflow: hidden;
        max-height: 200px;
        white-space: nowrap;
        text-overflow: ellipsis;
     }

    .read-more {
        color: #4ab2f1;
        border: 0px;
        background: none;
  }  
  
  .text-container .text {
        white-space: normal;  
    }

</style>

<script>
    $(document).ready(function () {
        $(".read-more").click(function () {
            var textContainer = $(this).closest(".text-container");
            var text = textContainer.find(".text");

            // Toggle the "read more" and "read less" text
            if (text.hasClass("expanded")) {
                text.removeClass("expanded");
                text.css("max-height", "200px");
                $(this).text("Read More");
            } else {
                text.addClass("expanded");
                text.css("max-height", "none");
                $(this).text("Read Less");
            }
        });
    });
</script>
<div class="page category-page">
    <div class="page-title">
        <h1>@Model.Name</h1>
    </div>
    <div class="page-body">
        @await Component.InvokeAsync("Widget", new { widgetZone = PublicWidgetZones.CategoryDetailsTop, additionalData = Model })
        @*description*@
        @if (!string.IsNullOrWhiteSpace(Model.Description))
    {
           <div class="category-description text-container">

                <div class="text">
                    @Html.Raw(Model.Description)
                </div>
                <button class="read-more">Read More</button>
            </div>
        }
        @await Component.InvokeAsync("Widget", new { widgetZone = PublicWidgetZones.CategoryDetailsBeforeSubcategories, additionalData = Model })
        @*subcategories*@
        @if (Model.SubCategories.Count > 0)
        {
            <div class="category-grid sub-category-grid">
                <div class="item-grid">
                    @foreach (var item in Model.SubCategories)
                    {
                        <div class="item-box">
                            <div class="sub-category-item">
                                <h2 class="title">
                                    <a href="@Url.RouteUrl("Category", new { SeName = item.SeName })" title="@item.PictureModel.Title">
                                        @item.Name
                                    </a>
                                </h2>
                                <div class="picture">
                                    <a href="@Url.RouteUrl("Category", new { SeName = item.SeName })" title="@item.PictureModel.Title">
                                        <img alt="@item.PictureModel.AlternateText" src="@item.PictureModel.ImageUrl" title="@item.PictureModel.Title" />
                                    </a>
                                </div>
                            </div>
                        </div>
                    }
                </div>
            </div>
        }
        @await Component.InvokeAsync("Widget", new { widgetZone = PublicWidgetZones.CategoryDetailsBeforeFeaturedProducts, additionalData = Model })
        @*featured products*@
        @if (Model.FeaturedProducts.Count > 0)
        {
            <div class="product-grid featured-product-grid">
                <div class="title">
                    <strong>@T("Products.FeaturedProducts")</strong>
                </div>
                <div class="item-grid">
                    @foreach (var item in Model.FeaturedProducts)
                    {
                        <div class="item-box">
                            @await Html.PartialAsync("_ProductBox", item)
                        </div>
                    }
                </div>
            </div>
        }
        @await Component.InvokeAsync("Widget", new { widgetZone = PublicWidgetZones.CategoryDetailsAfterFeaturedProducts, additionalData = Model })
        @await Html.PartialAsync("_CatalogSelectors", Model.CatalogProductsModel)
        @await Component.InvokeAsync("Widget", new { widgetZone = PublicWidgetZones.CategoryDetailsBeforeProductList, additionalData = Model })
        @{
            var catalogProductsViewData = new ViewDataDictionary(ViewData);
            catalogProductsViewData["fetchUrl"] = Html.Raw(Url.Action("GetCategoryProducts", "Catalog", new { categoryId = Model.Id }));
        }
        @await Html.PartialAsync("_CatalogProducts", Model.CatalogProductsModel, catalogProductsViewData)
        @await Component.InvokeAsync("Widget", new { widgetZone = PublicWidgetZones.CategoryDetailsBottom, additionalData = Model })
    </div>
</div>

2 weeks ago
Ive been looking at this some more - excuse my terminology - but it looks like the script isnt being ran - so from what i can gather - the .text element gets given a class of expanded on a click and then removed when clicked again IF expanded.
If i add the class expanded manually in the inspect function of chrome the text expands (but the button doesnt change wording) so I am assuming this is just the script not running at all.

Could it be 4.40.4 version i am using?

I cant beleive its so hard to try and do a basic function such as a read more button..

Thanks

Steve
2 weeks ago
Hi there,
Is it something like this you are looking to achieve?
https://www.simplydoorhandles.co.uk/door-handles-on-a-backplate
Regards,
James
2 weeks ago
jamesg wrote:
Hi there,
Is it something like this you are looking to achieve?
https://www.simplydoorhandles.co.uk/door-handles-on-a-backplate
Regards,
James


Hi James

Exactly like that.. if you take a look at my link to my site you can see the read more - but its dead..

I assume the theme is the issue - and its probably time i gave the site a refresh too.. maybe with a new theme and update to the latest version of NOP

Steve
2 weeks ago
Hi Steve,
I cannot see your site as there is an IP block from the UK.
I did it simply from CSS and Html, it is not what you are ultimately looking for but it works well for seo etc. Would you like the CSS and code?
Best regards,
James
2 weeks ago
jamesg wrote:
Hi Steve,
I cannot see your site as there is an IP block from the UK.
I did it simply from CSS and Html, it is not what you are ultimately looking for but it works well for seo etc. Would you like the CSS and code?
Best regards,
James


Hi James

Sorry i added a ipfilter as we were getting hammered with thousands of guest accounts per day and ended up with a 26gb DB log file. I have added the UK to allowed countries if you wanted to have a look.

Looking at the site its exactly what i am looking for (I assume its in the template file) I lieterally just need to it truncate longer descriptions so that the products arent pushed all the way down the page.  I'm still assuming that my theme / nop version may be causing an issue here. But I have that in the works and may even look at trying the theme your site is using as it seems to be a) very configurable and b) looks pretty good too

I would be very happy if you shared the code you used - it gives me another avenue to try

Steve
2 weeks ago
Hi Steve,
This is the CSS we used;

input[type='checkbox'] {
   display: none;
}
.txt-wrap-collabsible {
  margin-bottom: 1.2rem 0;
}
.txt-lbl-toggle {
  display: block;
  font-weight: bold;
  cursor: pointer;
  border-radius: 7px;
  transition: all 0.25s ease-out;
}
.txt-lbl-toggle:hover {
  color: #a6cf27;
}
.txt-lbl-toggle::before {
  content: ' ';
  display: inline-block;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  border-left: 5px solid currentColor;
  vertical-align: middle;
  margin-right: .7rem;
  transform: translateY(-2px);
  transition: transform .6s ease-out;
}
.txt-toggle:checked + .txt-lbl-toggle::before {
  transform: rotate(90deg) translateX(-3px);
}
.txt-collapsible-content {
  max-height: 0px;
  overflow: hidden;
  transition: max-height .6s ease-in-out;
}
.txt-toggle:checked + .txt-lbl-toggle + .txt-collapsible-content {
  max-height: 100vh;
}
.txt-toggle:checked + .txt-lbl-toggle {
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
}
.txt-collapsible-content .txt-content-inner {
   border-bottom-left-radius: 7px;
  border-bottom-right-radius: 7px;
  padding: .5rem 1rem;
  text-align: left;
}


And an example of the HTML you need in the category is;

<p>We have many fire extinguishers</p>
<div class="txt-wrap-collapsible"><input id="txt-collapsible" class="txt-toggle" type="checkbox" /><label class="txt-lbl-toggle" for="txt-collapsible">Read More...</label>
<div class="txt-collapsible-content">
<div class="txt-content-inner"
<p>They are the best in the market</p>
</div>
</div>
</div>

1 week ago
jamesg wrote:
Hi Steve,
This is the CSS we used;

input[type='checkbox'] {
   display: none;
}
.txt-wrap-collabsible {
  margin-bottom: 1.2rem 0;
}
.txt-lbl-toggle {
  display: block;
  font-weight: bold;
  cursor: pointer;
  border-radius: 7px;
  transition: all 0.25s ease-out;
}
.txt-lbl-toggle:hover {
  color: #a6cf27;
}
.txt-lbl-toggle::before {
  content: ' ';
  display: inline-block;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  border-left: 5px solid currentColor;
  vertical-align: middle;
  margin-right: .7rem;
  transform: translateY(-2px);
  transition: transform .6s ease-out;
}
.txt-toggle:checked + .txt-lbl-toggle::before {
  transform: rotate(90deg) translateX(-3px);
}
.txt-collapsible-content {
  max-height: 0px;
  overflow: hidden;
  transition: max-height .6s ease-in-out;
}
.txt-toggle:checked + .txt-lbl-toggle + .txt-collapsible-content {
  max-height: 100vh;
}
.txt-toggle:checked + .txt-lbl-toggle {
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
}
.txt-collapsible-content .txt-content-inner {
   border-bottom-left-radius: 7px;
  border-bottom-right-radius: 7px;
  padding: .5rem 1rem;
  text-align: left;
}


And an example of the HTML you need in the category is;

<p>We have many fire extinguishers</p>
<div class="txt-wrap-collapsible"><input id="txt-collapsible" class="txt-toggle" type="checkbox" /><label class="txt-lbl-toggle" for="txt-collapsible">Read More...</label>
<div class="txt-collapsible-content">
<div class="txt-content-inner"
<p>They are the best in the market</p>
</div>
</div>
</div>



Hi James

Thanks - so you add this to each 'description' text on each category? Ok its a way of doing it but thought hitting it with the category template would have been the way to go as you do it once and its automatic (admittedly there is not way of truncating it where you need it) Honestly I am stunned the a) its not standard using some shortcode and b) that nobody has developed a plugin that does it either to template or to text - eg just add something like @readmore or insert a readmore marker at the point you want it...

I'll take a look anyway and appreciate the time you have taken to follow this up

(sorry for the delay getting back to you - my wife has just had a child - so been a little busy!)

Steve
1 week ago
jamesg wrote:
Hi Steve,
This is the CSS we used;

input[type='checkbox'] {
   display: none;
}
.txt-wrap-collabsible {
  margin-bottom: 1.2rem 0;
}
.txt-lbl-toggle {
  display: block;
  font-weight: bold;
  cursor: pointer;
  border-radius: 7px;
  transition: all 0.25s ease-out;
}
.txt-lbl-toggle:hover {
  color: #a6cf27;
}
.txt-lbl-toggle::before {
  content: ' ';
  display: inline-block;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  border-left: 5px solid currentColor;
  vertical-align: middle;
  margin-right: .7rem;
  transform: translateY(-2px);
  transition: transform .6s ease-out;
}
.txt-toggle:checked + .txt-lbl-toggle::before {
  transform: rotate(90deg) translateX(-3px);
}
.txt-collapsible-content {
  max-height: 0px;
  overflow: hidden;
  transition: max-height .6s ease-in-out;
}
.txt-toggle:checked + .txt-lbl-toggle + .txt-collapsible-content {
  max-height: 100vh;
}
.txt-toggle:checked + .txt-lbl-toggle {
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
}
.txt-collapsible-content .txt-content-inner {
   border-bottom-left-radius: 7px;
  border-bottom-right-radius: 7px;
  padding: .5rem 1rem;
  text-align: left;
}


And an example of the HTML you need in the category is;

<p>We have many fire extinguishers</p>
<div class="txt-wrap-collapsible"><input id="txt-collapsible" class="txt-toggle" type="checkbox" /><label class="txt-lbl-toggle" for="txt-collapsible">Read More...</label>
<div class="txt-collapsible-content">
<div class="txt-content-inner"
<p>They are the best in the market</p>
</div>
</div>
</div>



Hi James

Do you use any other plugins as in content management plugins to make this easier or do you just copy and paste into each category as you need? It is working thanks - much appreciated - I was just looking at a way of inserting text as a widget kind of thing into the text - must like MS word Parts or i beleive wordpress has something similar

Steve