Skip to content

Commit

Permalink
Merge PR #784 into 14.0
Browse files Browse the repository at this point in the history
Signed-off-by pedrobaeza
  • Loading branch information
OCA-git-bot committed Aug 28, 2023
2 parents de48af3 + c333168 commit 8b5bdad
Show file tree
Hide file tree
Showing 25 changed files with 657 additions and 0 deletions.
6 changes: 6 additions & 0 deletions setup/website_sale_infinite_scroll/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
Empty file.
5 changes: 5 additions & 0 deletions website_sale_infinite_scroll/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright 2020 Advitus MB
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).

from . import models
from . import controllers
23 changes: 23 additions & 0 deletions website_sale_infinite_scroll/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright 2020 Advitus MB
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).

{
"name": "eCommerce Infinite Scroll",
"category": "Website",
"version": "14.0.1.0.0",
"author": "Advitus MB, Ooops, Cetmix, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/e-commerce",
"license": "LGPL-3",
"depends": ["website_sale"],
"data": [
"views/assets.xml",
"views/templates.xml",
"views/res_config_settings.xml",
],
"demo": [
"demo/demo_products.xml",
],
"maintainers": ["dessanhemrayev", "CetmixGitDrone"],
"application": False,
"installable": True,
}
4 changes: 4 additions & 0 deletions website_sale_infinite_scroll/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2020 Advitus MB
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).

from . import main
94 changes: 94 additions & 0 deletions website_sale_infinite_scroll/controllers/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import math

from odoo import http
from odoo.http import request

from odoo.addons.website_sale.controllers.main import WebsiteSale


class WebsiteSaleInfinityScroll(WebsiteSale):
@http.route()
def shop(self, page=0, category=None, ppg=False, search="", **post):
res = super().shop(
page=page,
category=category,
search=search,
ppg=self._get_shop_ppg(ppg),
**post
)
return request.render("website_sale.products", res.qcontext)

def _get_shop_ppg(self, ppg):
return (
request.website.shop_ppg + 1
if request.website.viewref("website_sale_infinite_scroll.scroll_products")
.sudo()
.active
else ppg
)

@http.route(
[
"""/website_sale_infinite_scroll""",
"""/website_sale_infinite_scroll/""" """page/<int:page>""",
"""/website_sale_infinite_scroll/"""
"""category/<model("product.public.category", """
""""[('website_id', 'in', (False, current_website_id))]")"""
""":category>""",
"""/website_sale_infinite_scroll/category/"""
"""<model("product.public.category", "[('website_id', 'in', """
"""(False, current_website_id))]"):category>/page/<int:page>""",
],
type="http",
auth="public",
methods=["POST"],
website=True,
)
def website_sale_infinite_scroll_get_page(
self, page=0, category=None, search="", ppg=False, **post
):
if ppg:
try:
ppg = int(ppg)
post["ppg"] = ppg
except ValueError:
ppg = False
if not ppg:
ppg = request.env["website"].get_current_website().shop_ppg or 20
old_ppg = ppg
old_page = page
if page > 0:
ppg = ppg * page
page = 1
res = super().shop(page=page, category=category, search=search, ppg=ppg, **post)
page_count = int(math.ceil(float(len(res.qcontext["products"])) / old_ppg))
if old_page > page_count:
return request.render("website_sale_infinite_scroll.empty_page")
res.qcontext.update(
{
"ppg": old_ppg,
"page": old_page,
}
)
return request.render(
"website_sale_infinite_scroll.infinite_products",
res.qcontext,
)

@http.route(
["/infinite_scroll_preloader"],
type="http",
auth="public",
website=True,
multilang=False,
sitemap=False,
)
def get_website_sale_infinite_scroll_preloader(self, **post):
website = request.website
response = request.redirect(
website.image_url(website, "infinite_scroll_preloader"), code=301
)
response.headers["Cache-Control"] = (
"public, max-age=%s" % http.STATIC_CACHE_LONG
)
return response
11 changes: 11 additions & 0 deletions website_sale_infinite_scroll/demo/demo_products.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" ?>
<odoo>
<data noupdate="1">
<function model="product.template" name="create">
<value
model="product.template"
eval="[{'name': 'product {num}'.format(num=x), 'website_published': True} for x in range(300)]"
/>
</function>
</data>
</odoo>
2 changes: 2 additions & 0 deletions website_sale_infinite_scroll/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import website
from . import res_config_settings
10 changes: 10 additions & 0 deletions website_sale_infinite_scroll/models/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from odoo import fields, models


class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"

website_sale_infinite_scroll_preloader = fields.Image(
related="website_id.infinite_scroll_preloader",
readonly=False,
)
21 changes: 21 additions & 0 deletions website_sale_infinite_scroll/models/website.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import base64

from odoo import fields, models, tools
from odoo.modules.module import get_resource_path


class Website(models.Model):
_inherit = "website"

def _default_preloader(self):
img_path = get_resource_path("web", "static/src/img/throbber-large.gif")
with tools.file_open(img_path, "rb") as f:
return base64.b64encode(f.read())

infinite_scroll_preloader = fields.Image(
max_width=170,
max_height=170,
string="eCommerce Infinite Scroll",
default=_default_preloader,
)
infinite_scroll_ppg = fields.Integer(default=24)
1 change: 1 addition & 0 deletions website_sale_infinite_scroll/readme/CONFIGURE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
To customize preloading icon, go to * General Settings > Website > Website sale infinite scroll preloader"
2 changes: 2 additions & 0 deletions website_sale_infinite_scroll/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Cetmix <https://cetmix.com>
* Dessan Hemrayev <dessanhemrayev@gmail.com>
2 changes: 2 additions & 0 deletions website_sale_infinite_scroll/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This module removes pagination in /shop page and replaces it with infinite scrolling of products.
In general settings > website, it's possible to customize the image to display while loading products.
1 change: 1 addition & 0 deletions website_sale_infinite_scroll/readme/USAGE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Go to /shop page > Customize > activate "Infinite Products Scroll"
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions website_sale_infinite_scroll/static/src/js/bus_longpolling.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
odoo.define("website_sale_infinite_scroll.Longpolling", function (require) {
"use strict";

var LongpollingBus = require("bus.Longpolling");

// Enable fast backward/forward from bfcache
LongpollingBus.include({
init: function () {
this._super.apply(this, arguments);
$(window).unbind("unload");
$(window).on(
"pagehige." + this._longPollingBusId,
this._onFocusChange.bind(this, {focus: false})
);
},
destroy: function () {
this._super.apply(this, arguments);
$(window).off("pagehige." + this.bus_id);
},
});
});
120 changes: 120 additions & 0 deletions website_sale_infinite_scroll/static/src/js/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
odoo.define("website_sale_infinite_scroll.main", function (require) {
"use strict";

var sAnimations = require("website.content.snippets.animation");
var core = require("web.core");
var _t = core._t;

sAnimations.registry.infinite_scroll = sAnimations.Class.extend({
selector: "#wrapwrap",
allow_load: true,
flag: true,
init: function () {
var self = this;
this._super.apply(this, arguments);
// Parse current page number and compute next one
var current_url = window.location.pathname;

if (current_url.indexOf("/shop") !== -1 && self._check_pagination()) {
var current_arguments = window.location.search;
self.current_page = 1;
if (current_url.indexOf("/page") === -1) {
current_url = current_url.replace(
"/shop",
"/shop/page/" + self.current_page
);
}
var match = current_url.match(/\/page\/(\d*)/);
self.current_page = match[1];
current_url = current_url.replace("/page/" + self.current_page, "");
self.next_page = self.current_page;
// Build fetch endpoint url
self.fetch_url =
current_url.replace("/shop", "/website_sale_infinite_scroll") +
"/page/" +
self.next_page +
current_arguments;
}
},

start: function () {
var current_url = window.location.pathname;
if (current_url.indexOf("/shop") !== -1) {
var self = this;
const container = this.el;
container.addEventListener("scroll", () => {
if (self._check_pagination()) {
self._onScroll();
}
});
}
},
_check_pagination: function () {
var pagination = document.querySelector(".products_pager .pagination");
if (!pagination) return false;
var style = window.getComputedStyle(pagination).display;
return style === "none";
},

load_next_page: function () {
var self = this;
if (self.flag) {
self.next_page++;
// Set page in fetch url
var url = self.fetch_url.replace(
"/page/" + self.current_page,
"/page/" + self.next_page
);

// Add spinner
var $spinner = $("<span/>", {
class: "website_sale_infinite_scroll-spinner",
text: _t("Loading more products..."),
});

const postData = {
csrf_token: core.csrf_token,
};
$.ajax({
url,
success: function (table) {
if (table && table !== "") {
// Self.$("tbody").append(table);
self.$("tbody").html(table);
} else {
self.flag = false;
}
},
// Error: edialog,
// shows the loader element before sending.
beforeSend: function () {
self.allow_load = false;
const date = new Date();
$spinner.css(
"background",
`url(/infinite_scroll_preloader?new=${date.getTime()}) center top no-repeat`
);
self.$el
.find(".o_wsale_products_grid_table_wrapper")
.append($spinner);
},
// Hides the loader after completion of request, whether successfull or failor.
complete: function () {
self.allow_load = true;
self.$el.find(".website_sale_infinite_scroll-spinner").remove();
},
type: "POST",
dataType: "html",
data: postData,
});
}
},

_onScroll: function () {
var self = this;
if (self.allow_load) {
self.load_next_page();
}
},
});
});
39 changes: 39 additions & 0 deletions website_sale_infinite_scroll/static/src/js/toors/toor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
odoo.define("website_sale_infinite_scroll.tour", function (require) {
"use strict";

var tour = require("web_tour.tour");
var ajax = require("web.ajax");

var steps = [
{
trigger: "#wrapwrap",
run: function () {
const url = "/website_sale_infinite_scroll/page/2";
ajax.post(url, {async: true}).then(function (table) {
console.log(table);
});
},
},
{
trigger: "#wrapwrap",
run: function () {
window.location.href = "/shop";
const url = "/website_sale_infinite_scroll/page/1000?ppg=False";
ajax.post(url, {async: true}).then(function (table) {
console.log(table);
});
},
},
];
tour.register(
"website_sale_infinite_scroll",
{
url: "/shop",
test: true,
},
steps
);
return {
steps: steps,
};
});
Loading

0 comments on commit 8b5bdad

Please sign in to comment.