[IMP] website: remove meta_data from params of filter, and design card

Call _get_filter_meta_data when needed instead to compute it only once and
give it from function to function, it is really trivial to compute and the
api of functions are simple from this way.

Avoid to use h4/h5 taf for styling bug use bootstrap feature for it.
The semantic of <div class='h4'/> vs <h4/> is not the same for SEO

Don't make call_to_action_url required

+ small typo

task-2446024
https://github.com/odoo/odoo/pull/65176
This commit is contained in:
Jeremy Kersten
2021-02-16 14:20:24 +00:00
parent 1d2dd3f76f
commit be49f9fb1f
3 changed files with 48 additions and 50 deletions
+9 -10
View File
@@ -728,18 +728,18 @@
<t t-set="fieldsImg" t-value="list(record['image_fields'].values())"/>
<t t-set="call_to_action_url" t-value="record['call_to_action_url']"/>
<div class="card h-100" t-att-data-url="call_to_action_url">
<h4 t-if="is_sample" class="o_ribbon_right bg-warning text-uppercase">Sample</h4>
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
<img t-if="len(fieldsImg) > 0" class="card-img-top p-3" loading="lazy" t-att-src="fieldsImg[0]"/>
<div class="card-body">
<h5 t-if="len(fields) > 0" class="card-title">
<div t-if="len(fields) > 0" class="card-title h5">
<t t-raw="fields[0]"/>
</h5>
</div>
<div t-if="len(fields) > 1" class="card-text">
<t t-raw="fields[1]"/>
</div>
</div>
<div class="card-footer d-flex align-items-center">
<div t-if="len(fields) > 2" class="card-text">
<div t-if="len(fields) > 2" class="card-text text-center">
<t t-raw="fields[2]"/>
</div>
<a t-if="call_to_action" class="btn btn-primary ml-auto" t-att-href="call_to_action_url">
@@ -753,12 +753,11 @@
<t t-foreach="to_generic(records)" t-as="record">
<t t-set="fields" t-value="list(record['fields'].values())"/>
<t t-set="fieldsImg" t-value="list(record['image_fields'].values())"/>
<t t-set="call_to_action_url" t-value="record['call_to_action_url']"/>
<div class="card h-100" t-att-data-url="call_to_action_url">
<h4 t-if="is_sample" class="o_ribbon_right bg-warning text-uppercase">Sample</h4>
<h5 t-if="len(fields) > 0" class="card-header">
<div class="card h-100" t-att-data-url="record['call_to_action_url']">
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
<div t-if="len(fields) > 0" class="card-header h5">
<t t-raw="fields[0]"/>
</h5>
</div>
<div class="card-body">
<img t-if="len(fieldsImg) > 0" class="card-img-top p-3" loading="lazy" t-att-src="fieldsImg[0]"/>
<div t-if="len(fields) > 1" class="card-text">
@@ -766,7 +765,7 @@
</div>
</div>
<div class="card-footer d-flex align-items-center">
<div t-if="len(fields) > 2" class="card-text">
<div t-if="len(fields) > 2" class="card-text w-100 text-center">
<t t-raw="fields[2]"/>
</div>
</div>
+38 -39
View File
@@ -60,23 +60,23 @@ class WebsiteSnippetFilter(models.Model):
if self.website_id and self.env['website'].get_current_website() != self.website_id:
return ''
meta_data = self._get_filter_meta_data()
records = self._prepare_values(meta_data, limit, search_domain)
records = self._prepare_values(limit, search_domain)
is_sample = with_sample and not records
if is_sample:
records = self._prepare_sample(meta_data)
records = self._prepare_sample()
View = self.env['ir.ui.view'].sudo().with_context(inherit_branding=False)
escaped_records = self._record_to_escaped_values(meta_data, records)
escaped_records = self._record_to_escaped_values(records)
content = View._render_template(template_key, dict(
records=escaped_records,
is_sample=is_sample,
to_generic=lambda record: self._to_generic(meta_data, records)
to_generic=self._to_generic,
)).decode('utf-8')
return [ET.tostring(el) for el in ET.fromstring('<root>%s</root>' % content).getchildren()]
def _prepare_values(self, meta_data, limit=None, search_domain=None):
def _prepare_values(self, limit=None, search_domain=None):
"""Gets the data and returns it the right format for render."""
self.ensure_one()
limit = limit and min(limit, self.limit) or self.limit
if self.filter_id:
filter_sudo = self.filter_id.sudo()
@@ -91,7 +91,7 @@ class WebsiteSnippetFilter(models.Model):
order=','.join(literal_eval(filter_sudo.sort)) or None,
limit=limit
)
return self._filter_records_to_values(meta_data, records)
return self._filter_records_to_values(records)
except MissingError:
_logger.warning("The provided domain %s in 'ir.filters' generated a MissingError in '%s'", domain, self._name)
return []
@@ -101,13 +101,12 @@ class WebsiteSnippetFilter(models.Model):
dynamic_filter=self,
limit=limit,
search_domain=search_domain,
meta_data=meta_data,
).sudo().run() or []
except MissingError:
_logger.warning("The provided domain %s in 'ir.actions.server' generated a MissingError in '%s'", search_domain, self._name)
return []
def _to_generic(self, meta_data, records):
def _to_generic(self, records):
"""Converts a list of dictionary records into the structure used by generic templates for rendering:
[{
@@ -123,32 +122,36 @@ class WebsiteSnippetFilter(models.Model):
'call_to_action_url': 'some/location'
}, ... , ...]
@param meta_data: OrderedDict result of _get_filter_meta_data
@param records: records as dictionaries of non-escaped values associated to field names
@return List of Dict matching the rendering structure for generic templates
"""
meta_data = self._get_filter_meta_data()
result = []
for record in records:
data = self._get_rendering_data_structure()
data = {
'fields': OrderedDict({}),
'image_fields': OrderedDict({}),
}
for field_name, field_widget in meta_data.items():
value = record[field_name]
if field_widget in ('binary', 'image'):
data['image_fields'][field_name] = value
else:
data['fields'][field_name] = value
data['call_to_action_url'] = record['call_to_action_url']
data['call_to_action_url'] = record.get('call_to_action_url')
result.append(data)
return result
def _record_to_escaped_values(self, meta_data, records):
def _record_to_escaped_values(self, records):
"""Converts a list of dictionary records into rendered values
@param meta_data: OrderedDict result of _get_filter_meta_data
@param records: records as dictionaries of non-escaped values associated to field names
@return List of Dict containing rendered values of each field
"""
meta_data = self._get_filter_meta_data()
result = []
for record in records:
data = {}
@@ -171,7 +174,7 @@ class WebsiteSnippetFilter(models.Model):
value, options)
else:
data[field_name] = self.escape_falsy_as_empty(value)
data['call_to_action_url'] = record['call_to_action_url']
data['call_to_action_url'] = record.get('call_to_action_url')
result.append(data)
return result
@@ -185,15 +188,16 @@ class WebsiteSnippetFilter(models.Model):
@return Tuple containing the field name and the field type
"""
field_name, _, field_widget = field_name.partition(":")
field = model._fields.get(field_name) if model else None
if field:
field_type = field.type
elif 'image' in field_name:
field_type = 'image'
elif 'price' in field_name:
field_type = 'monetary'
else:
field_type = 'text'
if not field_widget:
field = model._fields.get(field_name) if model else None
if field:
field_type = field.type
elif 'image' in field_name:
field_type = 'image'
elif 'price' in field_name:
field_type = 'monetary'
else:
field_type = 'text'
return field_name, field_widget or field_type
def _get_filter_meta_data(self):
@@ -210,35 +214,35 @@ class WebsiteSnippetFilter(models.Model):
meta_data[field_name] = field_widget
return meta_data
def _prepare_sample(self, meta_data, length=4):
def _prepare_sample(self, length=4):
"""
Generates sample data and returns it the right format for render.
@param meta_data: OrderedDict result of _get_filter_meta_data
@param length: Number of sample records to generate
@return Array of objets with a value associated to each name in field_names
"""
if not length:
return []
sample = []
model = self.env[self.filter_id.model_id] if self.filter_id else (
self.action_server_id.model_id if self.action_server_id else None)
sample_data = self._get_hardcoded_sample(model)
for index in range(0, length):
single_sample_data = sample_data[index % len(sample_data)].copy()
self._fill_sample(meta_data, single_sample_data, index)
self._fill_sample(single_sample_data, index)
sample.append(single_sample_data)
return sample
def _fill_sample(self, meta_data, sample, index):
def _fill_sample(self, sample, index):
"""
Fills the missing fields of a sample
@param meta_data: OrderedDict result of _get_filter_meta_data
@param sample: Data structure to fill with values for each name in field_names
@param index: Index of the sample within the dataset
"""
meta_data = self._get_filter_meta_data()
for field_name, field_widget in meta_data.items():
if field_name not in sample:
if field_widget == 'binary':
@@ -252,6 +256,7 @@ class WebsiteSnippetFilter(models.Model):
else:
sample[field_name] = _('Sample %s', index + 1)
sample['call_to_action_url'] = ''
return sample
def _get_hardcoded_sample(self, model):
"""
@@ -263,24 +268,18 @@ class WebsiteSnippetFilter(models.Model):
"""
return [{}]
@api.model
def _get_rendering_data_structure(self):
return {
'fields': OrderedDict({}),
'image_fields': OrderedDict({}),
}
def _filter_records_to_values(self, meta_data, records):
def _filter_records_to_values(self, records):
"""
Extract the fields from the data source and put them into a dictionary of values
Extract the fields from the data source 'records' and put them into a dictionary of values
@param meta_data: OrderedDict result of _get_filter_meta_data
@param records: Model records returned by the filter
@return List of dict associating the field value to each field name
"""
self.ensure_one()
meta_data = self._get_filter_meta_data()
values = []
model = self.env[self.filter_id.model_id]
Website = self.env['website']
+1 -1
View File
@@ -59,9 +59,9 @@ FieldMonetary = model.env['ir.qweb.field.monetary']
website = request.website.get_current_website()
dynamic_filter = model.env.context.get('dynamic_filter')
meta_data = model.env.context.get('meta_data')
limit = model.env.context.get('limit')
search_domain = model.env.context.get('search_domain')
meta_data = dynamic_filter._get_filter_meta_data()
domain = [('website_published', '=', True)] + website.website_domain() + (search_domain or [])
products = ProductProduct.search(domain, limit=limit)