$(() => { class ProductListing { constructor() { this.bind_filters(); this.bind_search(); this.restore_filters_state(); } bind_filters() { this.field_filters = {}; this.attribute_filters = {}; $('.product-filter').on('change', frappe.utils.debounce((e) => { const $checkbox = $(e.target); const is_checked = $checkbox.is(':checked'); if ($checkbox.is('.attribute-filter')) { const { attributeName: attribute_name, attributeValue: attribute_value } = $checkbox.data(); if (is_checked) { this.attribute_filters[attribute_name] = this.attribute_filters[attribute_name] || []; this.attribute_filters[attribute_name].push(attribute_value); } else { this.attribute_filters[attribute_name] = this.attribute_filters[attribute_name] || []; this.attribute_filters[attribute_name] = this.attribute_filters[attribute_name].filter(v => v !== attribute_value); } if (this.attribute_filters[attribute_name].length === 0) { delete this.attribute_filters[attribute_name]; } } else if ($checkbox.is('.field-filter')) { const { filterName: filter_name, filterValue: filter_value } = $checkbox.data(); if (is_checked) { this.field_filters[filter_name] = this.field_filters[filter_name] || []; this.field_filters[filter_name].push(filter_value); } else { this.field_filters[filter_name] = this.field_filters[filter_name] || []; this.field_filters[filter_name] = this.field_filters[filter_name].filter(v => v !== filter_value); } if (this.field_filters[filter_name].length === 0) { delete this.field_filters[filter_name]; } } const query_string = get_query_string({ field_filters: JSON.stringify(if_key_exists(this.field_filters)), attribute_filters: JSON.stringify(if_key_exists(this.attribute_filters)), }); window.history.pushState('filters', '', `${location.pathname}?` + query_string); $('.page_content input').prop('disabled', true); this.get_items_with_filters() .then(html => { $('.products-list').html(html); }) .then(data => { $('.page_content input').prop('disabled', false); return data; }) .catch(() => { $('.page_content input').prop('disabled', false); }); }, 1000)); } make_filters() { } bind_search() { $('input[type=search]').on('keydown', (e) => { if (e.keyCode === 13) { // Enter const value = e.target.value; if (value) { window.location.search = 'search=' + e.target.value; } else { window.location.search = ''; } } }); } restore_filters_state() { const filters = frappe.utils.get_query_params(); let {field_filters, attribute_filters} = filters; if (field_filters) { field_filters = JSON.parse(field_filters); for (let fieldname in field_filters) { const values = field_filters[fieldname]; const selector = values.map(value => { return `input[data-filter-name="${fieldname}"][data-filter-value="${value}"]`; }).join(','); $(selector).prop('checked', true); } this.field_filters = field_filters; } if (attribute_filters) { attribute_filters = JSON.parse(attribute_filters); for (let attribute in attribute_filters) { const values = attribute_filters[attribute]; const selector = values.map(value => { return `input[data-attribute-name="${attribute}"][data-attribute-value="${value}"]`; }).join(','); $(selector).prop('checked', true); } this.attribute_filters = attribute_filters; } } get_items_with_filters() { const { attribute_filters, field_filters } = this; const args = { field_filters: if_key_exists(field_filters), attribute_filters: if_key_exists(attribute_filters) }; return new Promise((resolve, reject) => { frappe.call('erpnext.portal.product_configurator.utils.get_products_html_for_website', args) .then(r => { if (r.exc) reject(r.exc); else resolve(r.message); }) .fail(reject); }); } } new ProductListing(); function get_query_string(object) { const url = new URLSearchParams(); for (let key in object) { const value = object[key]; if (value) { url.append(key, value); } } return url.toString(); } function if_key_exists(obj) { let exists = false; for (let key in obj) { if (obj.hasOwnProperty(key) && obj[key]) { exists = true; break; } } return exists ? obj : undefined; } });