Create custom portelt - mixture of news and events - plone

I'm trying to create a custom portelt which displays news or event items based on a keyword. I don't want to use the collects portlet facility. I've created a Python Script which fetches the necessary results like this:
from Products.CMFCore.utils import getToolByName
portal_catalog = getToolByName(context, 'portal_catalog')
return portal_catalog.searchResults(
Subject = 'Startseite',
end={'query': DateTime(),
'range': 'min'},
sort_on='start',
sort_limit=3,
review_state='external')[:5]
So this should fetch all objects with the review_state 'external' and the keyword (or subject) 'Startseite'. Now I've created a page template which is used to render a classic portelt:
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
i18n:domain="plone">
<body>
<div metal:define-macro="portlet"
tal:define="view context/##events_view;
results context/startpage_informations;
events_link view/all_events_link;
prev_events_link view/prev_events_link"
tal:condition="results">
<dl class="portlet" id="portlet-events">
<dt class="portletHeader">
<span class="portletTopLeft"></span>
<a href=""
tal:attributes="href events_link"
class="tile">
Wichtige Neuigkeiten:
</a>
<span class="portletTopRight"></span>
</dt>
<tal:events tal:repeat="obj results">
<dd class="portletItem"
tal:define="oddrow repeat/obj/odd"
tal:attributes="class python:test(oddrow, 'portletItem even', 'portletItem odd')">
<a href="#"
class="tile"
tal:attributes="href obj/getURL;
title obj/Description">
<img src="#" alt="" tal:replace="structure here/news_icon.gif" />
<span tal:replace="obj/pretty_title_or_id">
Some Event
</span>
<span class="portletItemDetails"
tal:define="starts python:toLocalizedTime(obj.start, long_format=1);
ends python:toLocalizedTime(obj.end, long_format=1);
startTime python:toLocalizedTime(obj.start,time_only=1);
endTime python:toLocalizedTime(obj.end,time_only=1);
startDay python:toLocalizedTime(obj.start, long_format=0);
endDay python:toLocalizedTime(obj.end, long_format=0);">
<span>
<tal:condition condition="obj/location">
<tal:location content="obj/location">Location</tal:location>,<br />
</tal:condition>
<tal:sameday tal:condition="python:startDay==endDay">
<span tal:condition="startDay" tal:replace="startDay">:[If this is an event, show its start time and date]</span><br />
Uhrzeit: <span tal:condition="startTime" tal:replace="startTime">[If this is an event, show its start time and date]</span> -
<span tal:condition="endTime" tal:replace="endTime">[If this is an event, show its start time and date]</span>
</tal:sameday>
<tal:multiday tal:condition="python:startDay!=endDay">
Vom <span tal:condition="starts" tal:replace="starts">[If this is a multi-day event, show its start date]</span><br />bis
<tal:hasendday tal:condition="ends">
<span tal:replace="ends">[If this is a multi-day event, show its end date]</span>
</tal:hasendday>
</tal:multiday>
</span>
</span>
</a>
</dd>
</tal:events>
</dl>
</div>
</body>
</html>

Related

Verifying Bs4 Parsing Output from a Website

I was trying to scrape this site when I was running into errors due to tags that I thought existed, but did not exist in the scraped html from Bs4.
Site: https://en.thejypshop.com/category/cdlp/59/
I manually verified that the parsed output from Bs4 was giving me a completely different view of the html than when I inspected the site itself; here is a comparison of the two (copied relevant html in the two pastebin links). I also tried scraping with different parsing options such as 'lxml', 'html.parser', etc. but to no avail.
(Bs4 Output): https://pastebin.com/tg4P5DFh
<div class="thumbnail">
<div class="prdImg">
<a href="/product/stray-kids-mini-album-maxident-case-ver/842/category/59/display/2/" name="anchorBoxName_842">
<img alt="" id="eListPrdImage842_2" src="https://cafe24img.poxo.com/jyp3602022/web/product/medium/202210/ca01b08c39232296f482b657be53aa4b.jpg" />
</a>
<span class="wish">
<img alt="Before add to wish list" categoryno="59" class="icon_img ec-product-listwishicon" icon_status="off" individual-set="F" login_status="F" productno="842" src="/web/upload/icon_202204271744355800.png" />
</span>
</div>
<div class="icon">
<div class="promotion"></div>
<div class="button">
<div class="option"></div>
<img alt="Add to cart" class="ec-admin-icon cart" onclick="category_add_basket('842','59', '2', 'A0000', false, '1', 'P0000BGK', 'B', 'T', '20');" src="/web/upload/icon_202204271744303700.png" />
<img alt="View larger image" onclick="zoom('842', '59', '2','', '');" src="//img.echosting.cafe24.com/design/skin/admin/en_US/btn_prd_zoom.gif" style="cursor:pointer" />
</div>
</div>
</div>
(html from Site): https://pastebin.com/2xfi4XTA
<div class="thumbnail">
<div class="prdImg">
<a href="/product/stray-kids-mini-album-maxident-case-ver/842/category/59/display/1/">
<img src="https://cafe24img.poxo.com/jyp3602022/web/product/medium/202210/ca01b08c39232296f482b657be53aa4b.jpg" id="eListPrdImage842_1" alt="">
</a>
</div>
<span class="pro_icon">
<img src="/web/upload/icon_202204271744355800.png" class="icon_img ec-product-listwishicon" alt="Before add to wish list" productno="842" categoryno="59" icon_status="off" login_status="F" individual-set="F">
<img src="/web/upload/icon_202204271744303700.png" onclick="category_add_basket('842','59', '1', 'A0000', false, '1', 'P0000BGK', 'B', 'T', '20');" alt="Add to cart" class="ec-admin-icon cart">
</span>
<span class="soldout_icon"></span>
</div>
Note that the <span class="soldout_icon"></span> tag does not appear in what Bs4 sees, among other things.
My guess as to why this is the case;
I am not using a headless browser, so some websites such as this one might not display the same thing.
There is some JS running in the background that Bs4 does not pick up on
Please let me know if any of my guesses are incorrect and what is actually going on!
Yes, you are right as
the second page is beeing built dynamicaly so you can't get the real html with bs4. Try to use combination of selenium and bs4 to get what you need. Here is a small script that finds some hidden divs and print them out. You should get deeper insight and simulate web surfing to catch the html when the page is fully developed. This one below is still in the process of construction.
import time
from bs4 import BeautifulSoup
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument('--ignore-certificate-errors')
options.add_argument('--incognito')
options.add_argument('--headless')
driver = webdriver.Chrome(options = options)
urls = ['https://en.thejypshop.com/category/cdlp/59/', 'https://pastebin.com/2xfi4XTA']
for url in urls:
data = driver.get(url)
time.sleep(1)
pg_html = driver.page_source
pg_html = pg_html.replace('<', '<').replace('>', '>')
soup = BeautifulSoup(pg_html, 'html.parser')
dv = soup.find_all('div', attrs={'class': 'thumbnail'})
dv1 = soup.find_all('span', attrs={'class': 'soldout_icon'})
try:
print(60 * '-')
print(dv[0])
except:
pass
print(60 * '-')
try:
print(dv1[0])
print(60 * '-')
except:
pass
''' R e s u l t :
------------------------------------------------------------
<div class="thumbnail">
<div class="prdImg">
<img alt="" id="eListPrdImage842_2" src="https://cafe24img.poxo.com/jyp3602022/web/product/medium/202210/ca01b08c39232296f482b657be53aa4b.jpg"/>
<span class="wish"><img alt="Before add to wish list" categoryno="59" class="icon_img ec-product-listwishicon" icon_status="off" individual-set="F" login_status="F" productno="842" src="/web/upload/icon_202204271744355800.png"/></span>
</div>
<div class="icon">
<div class="promotion"> </div>
<div class="button">
<div class="option"></div> <img alt="Add to cart" class="ec-admin-icon cart" onclick="category_add_basket('842','59', '2', 'A0000', false, '1', 'P0000BGK', 'B', 'T', '20');" src="/web/upload/icon_202204271744303700.png"/> <img alt="View larger image" onclick="zoom('842', '59', '2','', '');" src="//img.echosting.cafe24.com/design/skin/admin/en_US/btn_prd_zoom.gif" style="cursor:pointer"/> </div>
</div>
</div>
------------------------------------------------------------
<span class="soldout_icon"></span>
------------------------------------------------------------
------------------------------------------------------------
<div class="thumbnail">
</div>
------------------------------------------------------------
<span class="soldout_icon"></span>
------------------------------------------------------------
'''
Regards...

How to bind razor variable to vue attribute?

I am trying bind a razor variable to html attribute with vuejs.
The variable which i must use is "#culture". It is a string variable which gives me current culture information.
My code is:
<div class="dropdown-product-item" v-for="(item, index) in card.items">
<span class="dropdown-product-remove"><i class="icon-cross" v-bind:data-id="item.Id" v-on:click="removeFromCard"></i></span>
<a class="dropdown-product-thumb" v-bind:href="/#{Html.Raw(culture);}/item.Link">
<img v-bind:src="item.ResimUrl" v-bind:alt="item.Ad">
</a>
<div class="dropdown-product-info">
<a class="dropdown-product-title" v-bind:href="/#{Html.Raw(culture);}/item.Link">{{item.Ad}}</a>
<span class="dropdown-product-details" v-if="!item.IndirimliFiyat">{{pieces[index]}} x {{item.Fiyat.PriceString}}</span>
<span class="dropdown-product-details" v-else>{{pieces[index]}} x {{item.IndirimliFiyat.PriceString}}</span>
</div>
This code doesn't work. I only see white screen.
How to I do this? Could you help me?

Getting the value from a button text for thyme leaf

Ok, I have this somewhat complex piece of HTML that I have to integrate with. It is a button with a drop down (using aria) and I had to pass in a currency list and be able to select one of the dropdown elements (currency values) and update the button text with the selected value. I write a tiny bit of js and that works well. I use thymeleaf to pass in values to populate and that works well. I also need to read the values that were set from the post to the spring mvc controller but I always get a empty string for the value that I set via js.
here is the javascript
$(".currencyDropdown li a").click(function () {
var selText = $(this).text().trim();
var button = $("#currencyButton");
button.text(selText);
console.log("currency selected is:" + selText);
});
here is the html
<div class="col-sm-9 col-sm-offset-3 col-xs-12 form-row">
<div class="dropdown">
<button class="btn btn-default dropdown-toggle field-small"
type="button"
id="currencyButton"
name="currencyButton"
th:field="${pals.selectedCurrency}"
data-toggle="dropdown"
th:inline="text">
[[${pals.selectedCurrency}]]
<i class="fa fa-caret-down"></i>
</button>
<ul id="currencyDropdown"
class="dropdown-menu currencyDropdown"
role="menu"
aria-labelledby="currencyButton">
<li role="presentation"
th:each="currency:${pals.currencyList}">
<a role="menuitem"
tabindex="-1"
href="#"
th:inline="text">
[[${currency}]]
</a>
</li>
</ul>
</div>
What I am trying to read back in the spring mvc controller is the pals.selectedCurrency value and it is always empty. Something I am missing? I was playing around and tried setting value and field. In reality I want to read the inline text that my js inserts.
I think you must add a th:fragment on you button and change the text of the button via ajax from backing bean from server, not from javascript. It's something like this :
<form th:action="#{/PersonEdit/save(contract=${param.contract})}" th:object="${personBean}"
method="POST" th:if="${param.contract != null}">
... other form components
<div class="form-group">
<label class="col-sm-4 control-label"
th:text="#{person.edit.policy.tfoms}"></label>
<div class="col-sm-8">
<select class="form-control" th:field="*{tfoms}"
onchange="loadInsuranceCompanies()">
<option th:each="t : ${tfomses}"
th:value="${t.uidtfoms}"
th:text="${t.shortName}"
th:selected="${personBean.tfoms != null
and personBean.tfoms.equals(t)}"></option>
</select>
</div>
</div>
<div th:class="${#fields.hasErrors('insuranceCompany')}
? 'form-group has-error' : 'form-group'">
<label class="col-sm-4 control-label"
th:text="#{person.edit.policy.ic}"></label>
<div class="col-sm-8" id="insuranceCompaniesContent">
<select class="form-control" id="insuranceCompany"
name="insuranceCompany"
th:fragment="insuranceCompany">
<option th:each="i : ${insuranceCompanies}"
th:value="${i.uidinsurancecompany}"
th:text="${i.shortName}"
th:selected="${personBean.insuranceCompany != null
and personBean.insuranceCompany.equals(i)}"></option>
</select>
<div th:if="${#fields.hasErrors('insuranceCompany')}"
th:each="err : ${#fields.errors('insuranceCompany')}">
<span class="text-danger" th:text="${err}"></span><br/>
</div>
</div>
</div>
In my case I refreshing one dropdown via another.Then refresh this fragment via ajax on item selection
function loadInsuranceCompanies() {
var url = [[#{/PersonEdit/insuranceCompanies}]];
if ($('#tfoms').val() !== '') {
url = url + '/' + $('#tfoms').val();
}
$("#insuranceCompaniesContent").load(url);
}
I think the trouble can be because you using not a standard select as a dropdown.
Ok, I figured out a relatively simple answer to it. I have to use the html that was provided because of look and feel considerations from the customer.
so what I did was add a hidden input and set that from the java script.
$(".currencyDropdown li a").click(function () {
var selText = $(this).text().trim();
$("#currencyButton").text(selText);
$("#currencySelected").val(selText);
console.log("currency selected is:" + selText);
});
<input type="hidden"
id="currencySelected"
th:field="${pals.selectedCurrency}"/>
<button class="btn btn-default dropdown-toggle field-small"
type="button"
id="currencyButton"
data-toggle="dropdown"
th:inline="text">
[[${pals.selectedCurrency}]]
<i class="fa fa-caret-down"></i>
</button>
<ul id="currencyDropdown"
class="dropdown-menu currencyDropdown"
role="menu"
aria-labelledby="currencyButton">
<li role="presentation"
th:each="currency:${pals.currencyList}">
<a role="menuitem"
tabindex="-1"
href="#"
th:inline="text">
[[${currency}]]
</a>
</li>
</ul>
I see the correct values that were selected for my dropdown on the spring mvc controller and now I can get on with the rest of the stuff.

Rich Snippets Nesting Issue

I've never used Rich Snippets before, so this is a little bit of a learning curve for me. I believe my issue is a nesting problem but I can't find any documentation anywhere that explicitly states how to nest these properties correctly.
I'm wanting to index a single-product review with multiple reviews into Rich Snippets with classic ASP pulling in different data feilds, here is my code:
<div>
<div itemscope itemtype="http://data-vocabulary.org/Review">
<span itemprop="itemreviewed">Forma Stanzol</span><br />
By <span itemprop="reviewer"><%=formaStanzolReviewArray(0,i)%></span><br />
<time itemprop="dtreviewed" datetime="<%=FormatDateTime(formaStanzolReviewArray(1,i),2)%>"><%=FormatDateTime(formaStanzolReviewArray(1,i),2)%></time> <br />
<span itemprop="description"><%=formaStanzolComment%></span>
</div>
</div>
This returns the Error: No rich snippet will be generated for this data, because it appears to include multiple reviews of an item, but no aggregate review information.
So, I added a dummy Aggregate code with static values, here's what it looks like all together:
<div>
<div itemscope itemtype="http://data-vocabulary.org/Review">
<span itemprop="itemreviewed">Forma Stanzol</span><br />
By <span itemprop="reviewer"><%=formaStanzolReviewArray(0,i)%></span><br />
<time itemprop="dtreviewed" datetime="<%=FormatDateTime(formaStanzolReviewArray(1,i),2)%>"><%=FormatDateTime(formaStanzolReviewArray(1,i),2)%></time> <br />
<span itemprop="description"><%=formaStanzolComment%></span>
</div>
<div itemscope itemtype="http://data-vocabulary.org/Review-aggregate">
<span itemprop="itemreviewed">Forma Stanzol</span>
<span itemprop="rating" itemscope itemtype="http://data-vocabulary.org/Rating">
<span itemprop="average">9</span>
out of <span itemprop="best">10</span>
</span>
based on<span itemprop="count">5</span> user reviews.
</div>
</div>
This causes my "Reviews" to not error but then all of my "Aggregate Reviews" push out this Error: No rich snippet will be generated for this data, because it appears to include multiple aggregate reviews of many items, instead of a single aggregate review of one item.
Seems like it's working against itself no matter what I do, so that's why I believe this to be a nesting issue.
How can I fix this?
EDIT: Ideally, I don't event want the Aggregate view of this item. The reviewer, item name, review date, and review description is all I need.
EDIT EDIT: This code is also running in a For loop where its getting information from the database with each pass.
Ok so the issue here was that a website, with a single product, but multiple reviews needs only one "Review-Aggregate" and one "Rating" itemtype. However, multiple "Review" itemtypes must be used.
So, my For Loop creates a "Review" for each row in the database, using the related data feilds and then after the conditional statement, the "Review-Aggregate" and Rating" codes are placed.
Code:
For i = 0 to uBound(formaStanzolReviewArray,2)
reviewCount = reviewCount + 1
formaStanzolComment = trim(formaStanzolReviewArray(2,i))
'Do not show reviews with empty comments
If Not (formaStanzolComment = "") OR isNull(formaStanzolComment) Then
%>
<div>
<div itemscope itemtype="http://data-vocabulary.org/Review">
<span style="position: absolute; left: 9999px;" itemprop="itemreviewed">Forma Stanzol</span>
Rating: <span itemprop="rating"><%=formaStanzolReviewArray(3,i)%></span> -
By <span itemprop="reviewer"><%=formaStanzolReviewArray(0,i)%></span> -
<time itemprop="dtreviewed" datetime="<%=FormatDateTime(formaStanzolReviewArray(1,i),2)%>"><%=FormatDateTime(formaStanzolReviewArray(1,i),2)%></time> <br />
<span itemprop="description"><%=formaStanzolComment%></span>
</div>
</div>
<%
sumRating = sumRating + formaStanzolReviewArray(3,i)
End If
Next
ratingAvg = sumRating / reviewCount
%>
<div style="position: absolute; left: 9999px;">
<div itemscope itemtype="http://data-vocabulary.org/Review-aggregate">
<span itemprop="rating" itemscope itemtype="http://data-vocabulary.org/Rating">
<span itemprop="worst">1</span>
<span itemprop="average"><%=ratingAvg%></span>
out of <span itemprop="best">5</span>
</span>
based on <span itemprop="votes"><%=reviewCount%></span> ratings.
<span itemprop="count"><%=reviewCount%></span> user reviews.
</div>
</div>
<%
Think of it as multiple User reviews in the For Loop, but we collect all of those reviews once in the aggregate, and then give that aggregate a rating scale.
Hope this helps anyone having nesting issues.
Please Note: I am using classic ASP for this particular code.

Stars and aggregated rating are not shown when using schema.org markup and and Review in xhtml page

I'm trying to implement schema.org's microData format in my xhtml template.
Since I'm using xhtml templates, I needed to add
<div itemprop="reviews" itemscope="itemscope" itemtype="http://schema.org/Review">
instead of:
<div itemprop="reviews" itemscope itemtype="http://schema.org/Review">
otherwise my template wouldn't be parsed. I found the solution here
My markup looks like this:
<div itemscope="itemscope" itemtype="http://schema.org/Place">
<div itemprop="aggregateRating" itemscope="itemscope"
itemtype="http://schema.org/AggregateRating">
<span itemprop="ratingValue">#{company.meanRating}</span> stars -
based on <span itemprop="reviewCount">#{company.confirmedReviewCount}</span> reviews
</div>
<ui:repeat var="review" value="#{company.reverseConfirmedReviews}">
<div itemprop="reviews" itemscope="itemscope" itemtype="http://schema.org/Review">
<span itemprop="name">Not a happy camper</span> -
by <span itemprop="author">#{review.reviewer.firstName}</span>,
<div itemprop="reviewRating" itemscope="itemscope" itemtype="http://schema.org/Rating">
<span itemprop="ratingValue">1</span>/
<span itemprop="bestRating">5</span>stars
</div>
<span itemprop="description">#{review.text} </span>
</div>
</ui:repeat>
</div>
When testing this in http://www.google.com/webmasters/tools/richsnippets I'm not getting any stars back or aggregated review count
What am I doing wrong here?
Yes!!
The problem actually consisted of two errors, first somebody had named the div class to
"hReview-aggregate" which is appropriate when you implement Microformats not
Microdata
The second error was that I misunderstood the specification of schema.org.
This is how I end up doing:
<div class="box bigBox" itemscope="itemscope" itemtype="http://schema.org/LocalBusiness">
<span itemprop="name">#{viewCompany.name}</span>
<div class="subLeftColumn" style="margin-top:10px;" itemprop="aggregateRating" itemscope="itemscope" itemtype="http://schema.org/AggregateRating">
<div class="num">
<span class="rating" id="companyRating" itemprop="ratingValue">#{rating}</span>
</div>
<div>Grade</div>
<div class="num">
<span class="count" id="companyCount" itemprop="reviewCount">
#{confirmedReviewCount}
</span>
</div>
</div>
</div>
Hope this helps!!!!!
hey checkout how holidayhq guys have done it for this url : www.holidayiq.com/destinations/Lonavala-Overview.html
you can check there snippet on this tool : http://www.google.com/webmasters/tools/richsnippets
and google out this keyword "lonavala attractions" and you will see the same snippet, they have used microdata to generate this reviews in snippet, they have used typeof="v:Review-aggregate" and much more tags, have a look at it, its nice implementation of the reviews in snippet kind of work.

Resources