@ -0,0 +1,49 @@ |
|||
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg |
|||
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
|
|||
Product Search Snippet |
|||
====================== |
|||
This module helps to search products in category and all category wise. |
|||
|
|||
Configuration |
|||
============= |
|||
* No additional configurations needed |
|||
|
|||
Company |
|||
------- |
|||
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
|||
|
|||
License |
|||
------- |
|||
General Public License, Version 3 (AGPL v3). |
|||
(https://www.gnu.org/licenses/agpl-3.0-standalone.html) |
|||
|
|||
Credits |
|||
------- |
|||
* Developer: (V18) Nivedhya T, |
|||
(V17) Ajith V, |
|||
(V16) Farhana Jahan PT |
|||
* Contact: odoo@cybrosys.com |
|||
|
|||
Contacts |
|||
-------- |
|||
* Mail Contact : odoo@cybrosys.com |
|||
* Website : https://cybrosys.com |
|||
|
|||
Bug Tracker |
|||
----------- |
|||
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
|||
|
|||
Maintainer |
|||
========== |
|||
.. image:: https://cybrosys.com/images/logo.png |
|||
:target: https://cybrosys.com |
|||
|
|||
This module is maintained by Cybrosys Technologies. |
|||
|
|||
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
|||
|
|||
Further information |
|||
=================== |
|||
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,23 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from . import controllers |
|||
from . import models |
@ -0,0 +1,61 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
{ |
|||
'name': 'Product Search Snippet', |
|||
'version': '18.0.1.0.0', |
|||
'category': 'Website', |
|||
'summary': """Product Search Snippet for Website.""", |
|||
'description': """This module enables users to search for products |
|||
within a specific category or across all categories using the search |
|||
bar on the website snippet and redirect to its details.""", |
|||
'author': 'Cybrosys Techno Solutions', |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'maintainer': 'Cybrosys Techno Solutions', |
|||
'website': "https://cybrosys.com/", |
|||
'depends': ['website', 'sale_management'], |
|||
'data': [ |
|||
'views/snippets/search_snippet_templates.xml', |
|||
'views/snippets/product_search_templates.xml', |
|||
'views/snippets/product_details_templates.xml', |
|||
'views/snippets/selected_product_from_all_product_templates.xml', |
|||
'views/snippets/product_all_result_templates.xml', |
|||
'views/snippets/category_details_templates.xml', |
|||
'views/snippets/category_selected_product_templates.xml', |
|||
'views/snippets/selected_category_from_all_category_templates.xml', |
|||
'views/snippets/category_all_result_templates.xml', |
|||
'views/snippets/product_select_from_category_templates.xml', |
|||
], |
|||
'assets': { |
|||
'web.assets_frontend': [ |
|||
'website_product_search_snippet/static/src/css/website_product_search_snippet.scss', |
|||
'website_product_search_snippet/static/src/js/website_product_search_snippet.js', |
|||
'website_product_search_snippet/static/src/js/search_bar.js', |
|||
'website_product_search_snippet/static/src/xml/product_templates.xml', |
|||
'website_product_search_snippet/static/src/xml/category_templates.xml', |
|||
] |
|||
}, |
|||
'images': ['static/description/banner.jpg'], |
|||
'license': 'AGPL-3', |
|||
'installable': True, |
|||
'auto_install': False, |
|||
'application': False, |
|||
} |
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from . import website_product_search_snippet |
@ -0,0 +1,146 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from odoo import http |
|||
from odoo.http import request |
|||
|
|||
|
|||
class WebsiteSnippetPage(http.Controller): |
|||
"""Controller for setting routes.Pass all categories and |
|||
category wise products as array to a template""" |
|||
|
|||
@http.route('/category/form', type='http', auth='public', |
|||
website=True, csrf=False, sitemap=False, cache=300) |
|||
def category_page(self, **kw): |
|||
"""Function for rendering specific category and products of that |
|||
category into website""" |
|||
category = request.env['product.category'].sudo().browse( |
|||
int(kw.get('category_id'))) |
|||
parent = request.env['product.category'].sudo().browse( |
|||
int(kw.get('parent_id'))) |
|||
values = { |
|||
'category': category, |
|||
'products': request.env['product.template'].search( |
|||
[('categ_id', '=', category.id)]), |
|||
'products_category': request.env['product.template'].search( |
|||
[('category_id', '=', parent.id)]) |
|||
} |
|||
return http.request.render( |
|||
'website_product_search_snippet.category_snippet_img', values) |
|||
|
|||
@http.route('/selected/category/result', type='http', auth='public', |
|||
website=True, csrf=False, sitemap=False, cache=300) |
|||
def category_all_page(self, **kw): |
|||
"""Function for rendering specific category and products of that |
|||
category into website""" |
|||
category = request.env['product.category'].sudo().browse( |
|||
int(kw.get('category_id'))) |
|||
values = { |
|||
'category': category, |
|||
'products': request.env['product.template'].search( |
|||
[('categ_id', '=', category.id)]) |
|||
} |
|||
return http.request.render( |
|||
'website_product_search_snippet.all_category_snippet_img', values) |
|||
|
|||
@http.route('/selected/category/from/all_category/result', type='http', auth='public', |
|||
website=True, csrf=False, sitemap=False, cache=300) |
|||
def category_from_all_category_page(self, **kw): |
|||
"""Function for rendering specific category and products of that |
|||
category into website""" |
|||
category = request.env['product.category'].sudo().browse( |
|||
int(kw.get('category_id'))) |
|||
values = { |
|||
'category': category, |
|||
'products': request.env['product.template'].search( |
|||
[('categ_id', '=', category.id)]) |
|||
} |
|||
return http.request.render( |
|||
'website_product_search_snippet.category_from_all_category_snippet_img', values) |
|||
|
|||
@http.route('/product/form', type='http', auth='public', |
|||
website=True, csrf=False, sitemap=False, cache=300) |
|||
def product_page(self, **kw): |
|||
"""Function for rendering specific product into website""" |
|||
values = { |
|||
'products': request.env['product.template'].sudo().browse( |
|||
int(kw.get('product_id'))) |
|||
} |
|||
return http.request.render( |
|||
'website_product_search_snippet.products_snippet_img', values) |
|||
|
|||
@http.route('/selected/product/from/category', type='http', auth='public', |
|||
website=True, csrf=False, sitemap=False, cache=300) |
|||
def selected_product_page(self, **kw): |
|||
"""Function for rendering specific product into website""" |
|||
values = { |
|||
'products': request.env['product.template'].sudo().browse( |
|||
int(kw.get('product_id'))) |
|||
} |
|||
return http.request.render( |
|||
'website_product_search_snippet.selected_products_from_category_snippet_img', |
|||
values) |
|||
|
|||
@http.route('/all/product/selected/product/details', type='http', |
|||
auth='public', |
|||
website=True, csrf=False, sitemap=False, cache=300) |
|||
def product_all_page(self, **kw): |
|||
"""Function for rendering specific product into website""" |
|||
values = { |
|||
'products': request.env['product.template'].sudo().browse( |
|||
int(kw.get('product_id'))) |
|||
} |
|||
return http.request.render( |
|||
'website_product_search_snippet.all_products_snippet_img', values) |
|||
|
|||
@http.route('/select/product/from/category', type='http', auth='public', |
|||
website=True, csrf=False, sitemap=False, cache=300) |
|||
def product_category_all_page(self, **kw): |
|||
"""Function for rendering specific product into website""" |
|||
values = { |
|||
'products': request.env['product.template'].sudo().browse( |
|||
int(kw.get('product_id'))) |
|||
} |
|||
return http.request.render( |
|||
'website_product_search_snippet.products_category_snippet_img', |
|||
values) |
|||
|
|||
@http.route('/product/form/all/results', type='http', auth='public', |
|||
website=True, csrf=False, sitemap=False, cache=300) |
|||
def product_page_result(self): |
|||
"""Function for rendering all products into website""" |
|||
values = { |
|||
'products': request.env['product.template'].search([]) |
|||
} |
|||
return http.request.render( |
|||
"website_product_search_snippet.product_all_result_template", |
|||
values) |
|||
|
|||
@http.route('/category/form/all/results', type='http', auth='public', |
|||
website=True, csrf=False, sitemap=False, cache=300) |
|||
def category_page_result(self): |
|||
"""Function for rendering all categories into website""" |
|||
values = {'category': request.env['product.category'].search( |
|||
[('id', '!=', request.env.ref('product.product_category_all').id), |
|||
('id', '!=', request.env.ref('product.product_category_1').id)])} |
|||
return http.request.render( |
|||
"website_product_search_snippet.category_all_result_template", |
|||
values) |
@ -0,0 +1,5 @@ |
|||
## Module <website_product_search_snippet> |
|||
#### 19.12.2024 |
|||
#### Version 18.0.1.0.0 |
|||
##### ADD |
|||
- Initial commit for Product Search Snippet |
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from . import product_template |
@ -0,0 +1,81 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class ProductTemplate(models.Model): |
|||
""" Inherit product_template model for fetch products and categories to |
|||
frontend""" |
|||
_inherit = 'product.template' |
|||
|
|||
parent_category_id = fields.Many2one("product.category", |
|||
string="Parent Category") |
|||
category_boolean = fields.Boolean(default=True) |
|||
category_id = fields.Char(string='Parent Category', |
|||
compute="_compute_parent_id") |
|||
|
|||
@api.depends('category_boolean') |
|||
def _compute_parent_id(self): |
|||
""" Get the parent category of the product""" |
|||
self.category_id = self.categ_id.parent_id.id |
|||
|
|||
@api.model |
|||
def search_products(self, qry): |
|||
""" Search all products in product.template, |
|||
and pass searched products into templates """ |
|||
products = self.env['product.template'].search([('name', 'ilike', qry)]) |
|||
return [[product.name, product.id, |
|||
product.list_price, |
|||
'/web/image/product.template/{}/image_512/'.format(product.id), |
|||
product.currency_id.symbol, ] |
|||
for product in products] |
|||
|
|||
@api.model |
|||
def product_category(self, qry): |
|||
""" Search all category in product_category, |
|||
and pass category into another template """ |
|||
category = self.env['product.category'].search( |
|||
[('id', '!=', self.env.ref('product.product_category_all').id), |
|||
('name', 'ilike', qry)]) |
|||
return [[category.name, category.id, category.parent_id.name, |
|||
category.parent_id.id, |
|||
category.product_count] |
|||
for category in category] |
|||
|
|||
@api.model |
|||
def search_all_categories(self): |
|||
""" Search products in all categories """ |
|||
products = self.env['product.template'].search([]) |
|||
return [[product.name, product.id, |
|||
product.list_price, |
|||
'/web/image/product.template/{}/image_512/'.format(product.id), |
|||
product.currency_id.symbol, ] |
|||
for product in products] |
|||
|
|||
@api.model |
|||
def product_all_categories(self): |
|||
""" Search all product categories """ |
|||
categories = self.env['product.category'].search([ |
|||
('id', '!=', self.env.ref('product.product_category_all').id)]) |
|||
return [[category.name, category.id, category.parent_id.name, |
|||
category.parent_id.id, category.product_count] |
|||
for category in categories] |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 628 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 210 KiB |
After Width: | Height: | Size: 209 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 495 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 624 B |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 214 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 929 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 542 B |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 183 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 600 B |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 462 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 926 B |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 800 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 189 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 875 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 93 KiB |
After Width: | Height: | Size: 93 KiB |
After Width: | Height: | Size: 189 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 1.0 MiB |
After Width: | Height: | Size: 155 KiB |
After Width: | Height: | Size: 111 KiB |
After Width: | Height: | Size: 113 KiB |
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 130 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 880 KiB |
After Width: | Height: | Size: 130 KiB |
After Width: | Height: | Size: 8.6 KiB |
@ -0,0 +1,25 @@ |
|||
.heading{ |
|||
color: #fff6f8; |
|||
background: #575758; |
|||
font-size: 47px; |
|||
font-weight: bold; |
|||
} |
|||
.search_bar{ |
|||
margin-left: 47px; |
|||
border-radius: 15px; |
|||
} |
|||
.search_container{ |
|||
background: #9c9a9a |
|||
} |
|||
#sub_temp{ |
|||
background: #e9e9f1; |
|||
} |
|||
#category_template{ |
|||
background: #e9e9f1; |
|||
} |
|||
#table_header { |
|||
background-color: #bababa; |
|||
color: white; |
|||
} |
|||
#table_row:nth-child(even){background-color: #ededed} |
|||
#category_table:nth-child(even){background-color: #c3c3c3} |
After Width: | Height: | Size: 14 KiB |
@ -0,0 +1,52 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
import publicWidget from "@web/legacy/js/public/public_widget"; |
|||
|
|||
|
|||
publicWidget.registry.portalDetails = publicWidget.Widget.extend({ |
|||
/** |
|||
* This widget handles search functionality within a product table on the website. |
|||
* It listens for keyup events on the search input field and filters table rows |
|||
* based on the user's input. |
|||
*/ |
|||
selector: '.product_search_bar', |
|||
events: { |
|||
'keyup .search_product_bar': '_onKeyUp', |
|||
}, |
|||
/** |
|||
* Initializes the widget and starts the functionality. |
|||
* |
|||
* @returns {Promise} - Resolves when the widget has fully started. |
|||
*/ |
|||
start: function () { |
|||
this._super.apply(this, arguments); |
|||
}, |
|||
/** |
|||
* Handles the keyup event to filter table data. |
|||
* |
|||
* This function retrieves the value from the search input field, converts it to |
|||
* uppercase, and then compares it with the text content of each table cell. |
|||
* Rows that contain a match are displayed, while others are hidden. |
|||
* |
|||
* @private |
|||
*/ |
|||
_onKeyUp: function () { |
|||
var input, filter, table, tr, td, i, txtValue; |
|||
input = this.$el.find("#searchBarInput")[0]; |
|||
filter = input.value.toUpperCase(); |
|||
table = this.$el.find("#category_table") |
|||
tr = table[0].children.category_table_body.children; |
|||
for (i = 0; i < tr.length; i++) { |
|||
td = tr[i].children; |
|||
for (var j = 0; j < td.length; j++) { |
|||
txtValue = td[j].textContent || td[j].innerText; |
|||
if (txtValue.toUpperCase().indexOf(filter) > -1) { |
|||
tr[i].style.display = ""; |
|||
break; |
|||
} else { |
|||
tr[i].style.display = "none"; |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
}); |
@ -0,0 +1,135 @@ |
|||
/** @odoo-module **/ |
|||
import publicWidget from "@web/legacy/js/public/public_widget"; |
|||
import { rpc } from "@web/core/network/rpc"; |
|||
import {renderToElement} from "@web/core/utils/render"; |
|||
|
|||
var Dynamic = publicWidget.Widget.extend({ |
|||
selector: '.dynamic_search_snippet', |
|||
events: { |
|||
'click .search_container': '_onClick', |
|||
'keyup .search_bar': '_onKeyUp', |
|||
'change .category_options': '_filterProducts', |
|||
}, |
|||
/** |
|||
* _onClick: Clears the search input field. |
|||
* |
|||
* This function is triggered when a specific element is clicked. It clears the value of |
|||
* the input field with the ID `#searchInput`. |
|||
* |
|||
* Functionality: |
|||
* 1. Locates the input field with the ID `#searchInput` within the current element (`this.$el`). |
|||
* 2. Sets the value of the `#searchInput` field to an empty string, effectively clearing any text that was entered. |
|||
*/ |
|||
_onClick: function () { |
|||
this.$el.find('#searchInput').val(""); |
|||
}, |
|||
/** |
|||
* _onKeyUp: Asynchronously searches and filters products based on the user's input and selected category. |
|||
* |
|||
* This function is triggered when a key is released while typing in a search input field. |
|||
* It captures the current search query and the selected category, then calls the appropriate |
|||
* Odoo model method to fetch the relevant products. The fetched products are rendered in the |
|||
* specified HTML element using the corresponding QWeb template. |
|||
* |
|||
* @param {Object} ev - The event object associated with the keyup action. |
|||
* |
|||
* Functionality: |
|||
* 1. Captures the selected category from a dropdown menu with the class `.category_options`. |
|||
* 2. Retrieves the user's search query from the input field. |
|||
* 3. If "All Categories" is selected: |
|||
* - Calls the `search_products` method on the `product.template` model with the search query as an argument. |
|||
* - Renders the result using the 'website_product_search_snippet.product_template' template. |
|||
* 4. If "Category" is selected: |
|||
* - Calls the `product_category` method on the `product.template` model with the search query as an argument. |
|||
* - Renders the result using the 'website_product_search_snippet.product_category' template. |
|||
* 5. Updates the HTML element with the class `.qweb_product_id` to display the filtered products based on the search query and selected category. |
|||
* |
|||
* Note: The function uses `jsonrpc` to make RPC calls to the Odoo backend. |
|||
*/ |
|||
_onKeyUp: async function (ev) { |
|||
var self = this; |
|||
var category = this.$el.find(".category_options").find(":selected").text(); |
|||
var qry = $(ev.currentTarget).val() |
|||
if (category === "All Categories") { |
|||
await rpc('/web/dataset/call_kw', { |
|||
model: 'product.template', |
|||
method: 'search_products', |
|||
args: [qry], |
|||
kwargs: {}, |
|||
}).then(function (result) { |
|||
self.$('.qweb_product_id').html(""); |
|||
self.$('.qweb_product_id').append(renderToElement('website_product_search_snippet.product_template', { |
|||
result: result |
|||
})); |
|||
}); |
|||
} |
|||
if (category === "Category") { |
|||
var self = this; |
|||
await rpc('/web/dataset/call_kw', { |
|||
model: 'product.template', |
|||
method: 'product_category', |
|||
args: [qry], |
|||
kwargs: {}, |
|||
}).then(function (result) { |
|||
self.$('.qweb_product_id').html(""); |
|||
self.$('.qweb_product_id').append(renderToElement('website_product_search_snippet.product_category', { |
|||
result: result |
|||
})); |
|||
}); |
|||
} |
|||
}, |
|||
/** |
|||
* _filterProducts: Asynchronously filters products based on the selected category. |
|||
* |
|||
* This function is triggered by an event (e.g., a change in category selection). |
|||
* It checks the selected category from a dropdown menu and calls the appropriate |
|||
* Odoo model method to fetch the relevant products. The fetched products are then |
|||
* rendered in the specified HTML element using the corresponding QWeb template. |
|||
* |
|||
* @param {Object} ev - The event object associated with the action triggering this function. |
|||
* |
|||
* Functionality: |
|||
* 1. Retrieves the selected category from a dropdown menu with class `.category_options`. |
|||
* 2. If "All Categories" is selected, it calls the `search_all_categories` method |
|||
* on the `product.template` model to fetch all products, and renders the result |
|||
* using the 'website_product_search_snippet.product_template' template. |
|||
* 3. If "Category" is selected, it calls the `product_all_categories` method on |
|||
* the `product.template` model to fetch products by category, and renders the |
|||
* result using the 'website_product_search_snippet.product_category' template. |
|||
* 4. Updates the HTML element with class `.qweb_product_id` to display the filtered products. |
|||
* |
|||
* Note: The function uses `jsonrpc` to make RPC calls to the Odoo backend. |
|||
*/ |
|||
_filterProducts: async function (ev) { |
|||
var self = this |
|||
var category = this.$el.find(".category_options").find(":selected").text(); |
|||
if (category === "All Categories") { |
|||
await rpc('/web/dataset/call_kw', { |
|||
model: 'product.template', |
|||
method: 'search_all_categories', |
|||
args: [], |
|||
kwargs: {} |
|||
}).then(function (result) { |
|||
self.$('.qweb_product_id').html(""); |
|||
self.$('.qweb_product_id').append(renderToElement('website_product_search_snippet.product_template', { |
|||
result: result |
|||
})); |
|||
}); |
|||
} |
|||
if (category === "Category") { |
|||
await rpc('/web/dataset/call_kw', { |
|||
model: 'product.template', |
|||
method: 'product_all_categories', |
|||
args: [], |
|||
kwargs: {} |
|||
}).then(function (result) { |
|||
self.$('.qweb_product_id').html(""); |
|||
self.$('.qweb_product_id').append(renderToElement('website_product_search_snippet.product_category', { |
|||
result: result |
|||
})); |
|||
}); |
|||
} |
|||
}, |
|||
}); |
|||
publicWidget.registry.dynamic_search_snippet = Dynamic; |
|||
return Dynamic; |
@ -0,0 +1,60 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<!--When the key is pressed in the search bar the searched |
|||
category will be shown with its parent category--> |
|||
<templates id="template" xml:space="preserve"> |
|||
<t t-name="website_product_search_snippet.product_category"> |
|||
<div class="container" id="category_template"> |
|||
<section> |
|||
<form id="category_form"> |
|||
<div style="height:50px"/> |
|||
<center> |
|||
<h3>Categories</h3> |
|||
</center> |
|||
<t t-if="result.length === 0"> |
|||
<p class="text-center">No results found. Please try another search.</p> |
|||
</t> |
|||
<div style="height:20px"/> |
|||
<table class="table"> |
|||
<thead id="table_header"> |
|||
<td><b>Parent Category</b></td> |
|||
<td><b>Category</b></td> |
|||
</thead> |
|||
<tbody id="table_category_body" class="body"> |
|||
<t t-set="result_limit" t-value="5"/> |
|||
<t t-set="counter" t-value="0"/> |
|||
<t t-foreach="result" t-as="category" t-key="result"> |
|||
<t t-if="counter < result_limit"> |
|||
<tr id="table_row"> |
|||
<td><t t-esc="category[2]"/></td> |
|||
<t t-if="category[4] === 0"> |
|||
<td><a t-attf-href="/category/form?category_id=#{category[1]}&parent_id=#{category[3]}" |
|||
loading="fast" style="color: #de3434;"><t t-esc="category[0]" |
|||
/></a></td> |
|||
</t> |
|||
<t t-else=""> |
|||
<td><a t-attf-href="/category/form?category_id=#{category[1]}&parent_id=#{category[3]}" |
|||
loading="fast"><t t-esc="category[0]" |
|||
/></a></td> |
|||
</t> |
|||
</tr> |
|||
</t> |
|||
<t t-else=""> |
|||
<tr id="table_row_hidden" class="d-none"> |
|||
<td><t t-esc="category[2]"/></td> |
|||
<td><a t-attf-href="/category/form?category_id=#{category[1]}" |
|||
loading="fast"><t t-esc="category[0]" |
|||
/></a></td> |
|||
</tr> |
|||
</t> |
|||
<t t-set="counter" t-value="counter+1"/> |
|||
</t> |
|||
</tbody> |
|||
</table> |
|||
<a t-attf-href="/category/form/all/results" |
|||
style="margin-left: 38%;">See All Categories</a> |
|||
</form> |
|||
</section> |
|||
<div style="height:20px"/> |
|||
</div> |
|||
</t> |
|||
</templates> |
@ -0,0 +1,61 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<!--When the key is pressed in the search bar the searched products |
|||
will be shown with their price and image--> |
|||
<templates id="template" xml:space="preserve"> |
|||
<t t-name="website_product_search_snippet.product_template"> |
|||
<div class="container" id="sub_temp"> |
|||
<section cdata-vxml="001"> |
|||
<form id="product_form" style="background-color: #f3f3f3;"> |
|||
<div style="height:50px"/> |
|||
<center> |
|||
<h3 style="margin-left: 0%;">Products</h3> |
|||
</center> |
|||
<t t-if="result.length === 0"> |
|||
<p class="text-center">No results found. Please try another search.</p> |
|||
</t> |
|||
<div style="height:20px"/> |
|||
<table class="table"> |
|||
<thead id="table_header"> |
|||
<td><b>Image</b></td> |
|||
<td><b>Product</b></td> |
|||
<td style="padding-left:2%;"><b> </b></td> |
|||
<td><b>Price</b></td> |
|||
</thead> |
|||
<tbody id="table_body" class="body"> |
|||
<t t-set="result_limit" t-value="5"/> |
|||
<t t-set="counter" t-value="0"/> |
|||
<t t-foreach="result" t-as="product" t-key="result"> |
|||
<t t-if="counter < result_limit"> |
|||
<tr id="table_row"> |
|||
<td><img t-att-src="product[3]" |
|||
style="width:25%;"/></td> |
|||
<td><a t-attf-href="/product/form?product_id=#{product[1]}" |
|||
loading="fast"><t t-esc="product[0]" |
|||
/></a></td> |
|||
<td style="padding-left:2%;"><t t-esc="product[4]"/></td> |
|||
<td><t t-esc="product[2]"/></td> |
|||
</tr> |
|||
</t> |
|||
<t t-else=""> |
|||
<tr id="table_row_hidden" class="d-none"> |
|||
<td><img t-att-src="product[3]" |
|||
style="width:25%;"/></td> |
|||
<td><a t-attf-href="/product/form?product_id=#{product[1]}" |
|||
loading="fast"><t t-esc="product[0]" |
|||
/></a></td> |
|||
<td style="padding-left:2%;"><t t-esc="product[4]"/></td> |
|||
<td><t t-esc="product[2]"/></td> |
|||
</tr> |
|||
</t> |
|||
<t t-set="counter" t-value="counter+1"/> |
|||
</t> |
|||
</tbody> |
|||
</table> |
|||
<a t-attf-href="/product/form/all/results" |
|||
style="margin-left: 38%;">See All Products</a> |
|||
</form> |
|||
</section> |
|||
<div style="height:20px"/> |
|||
</div> |
|||
</t> |
|||
</templates> |
@ -0,0 +1,73 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!--When clicking on 'See All Category' rendering a page the route as |
|||
/category/form/all/results,where the categories are displayed--> |
|||
<template id="category_all_result_template" name="Category results Snippet"> |
|||
<t t-call="website.layout"> |
|||
<section class="row category_result_search_bar" loading="eager"> |
|||
<div class="container"> |
|||
<div style="height:20px"/> |
|||
<div class="back_button" align="left"> |
|||
<a t-attf-href="/" name="create" |
|||
style="margin-left: 13%;font-weight: bold;">Back |
|||
</a> |
|||
</div> |
|||
<div style="height:20px"/> |
|||
<center> |
|||
<form align="center" id="search_result" |
|||
action="/category/form/all/results"> |
|||
<div style="height:20px"/> |
|||
<div style="height:20px"/> |
|||
<center> |
|||
<h3 style="font-size: 26px;">All Categories |
|||
</h3> |
|||
</center> |
|||
<table class="table" |
|||
style="width: 66%;margin-left: 17%;"> |
|||
<thead id="table_header"> |
|||
<td> |
|||
<b>Parent Category</b> |
|||
</td> |
|||
<td> |
|||
<b>Category</b> |
|||
</td> |
|||
</thead> |
|||
<tbody id="table_category_body" |
|||
class="body"> |
|||
<t t-foreach="category" t-as="product"> |
|||
<tr style="nth-child(even){background-color: #f2f2f2}" |
|||
id="category_table"> |
|||
<td> |
|||
<t t-esc="product.parent_id.name"/> |
|||
</td> |
|||
<t t-if="product.product_count"> |
|||
<td> |
|||
<a t-attf-href="/selected/category/from/all_category/result?category_id=#{product.id}" |
|||
loading="fast"> |
|||
<t t-esc="product.name" |
|||
/> |
|||
</a> |
|||
</td> |
|||
</t> |
|||
<t t-else=""> |
|||
<td> |
|||
<a t-attf-href="/selected/category/from/all_category/result?category_id=#{product.id}" |
|||
loading="fast" |
|||
style="color: #de3434;"> |
|||
<t t-esc="product.name" |
|||
/> |
|||
</a> |
|||
</td> |
|||
</t> |
|||
</tr> |
|||
</t> |
|||
</tbody> |
|||
</table> |
|||
</form> |
|||
</center> |
|||
</div> |
|||
</section> |
|||
<div style="height:20px"/> |
|||
</t> |
|||
</template> |
|||
</odoo> |