update
This commit is contained in:
432
iadmin/themes/default/js/bundle/product/catalog.js
Normal file
432
iadmin/themes/default/js/bundle/product/catalog.js
Normal file
@@ -0,0 +1,432 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
/* eslint-disable no-unused-vars, no-unreachable */
|
||||
|
||||
const {$} = window;
|
||||
|
||||
$(document).ready(() => {
|
||||
const form = $('form#product_catalog_list');
|
||||
|
||||
/*
|
||||
* Tree behavior: collapse/expand system and radio button change event.
|
||||
*/
|
||||
$('div#product_catalog_category_tree_filter').categorytree();
|
||||
$('div#product_catalog_category_tree_filter div.radio > label > input:radio').change(function () {
|
||||
if ($(this).is(':checked')) {
|
||||
$('form#product_catalog_list input[name="filter_category"]').val($(this).val());
|
||||
$('form#product_catalog_list').submit();
|
||||
}
|
||||
});
|
||||
$('div#product_catalog_category_tree_filter ~ div button, div#product_catalog_category_tree_filter ul')
|
||||
.on('click', () => {
|
||||
categoryFilterButtons();
|
||||
});
|
||||
categoryFilterButtons();
|
||||
|
||||
/*
|
||||
* Click on a column header ordering icon to change orderBy / orderWay (location.href redirection)
|
||||
*/
|
||||
$('[psorderby][psorderway]', form).click(function () {
|
||||
const orderBy = $(this).attr('psorderby');
|
||||
const orderWay = $(this).attr('psorderway');
|
||||
productOrderTable(orderBy, orderWay);
|
||||
});
|
||||
|
||||
/*
|
||||
* Checkboxes behavior with bulk actions
|
||||
*/
|
||||
$('input:checkbox[name="bulk_action_selected_products[]"]', form).change(() => {
|
||||
updateBulkMenu();
|
||||
});
|
||||
|
||||
/*
|
||||
* Filter columns inputs behavior
|
||||
*/
|
||||
$('tr.column-filters input:text, tr.column-filters select', form).on('change input', () => {
|
||||
productCatalogFilterChanged = true;
|
||||
updateFilterMenu();
|
||||
});
|
||||
|
||||
/*
|
||||
* Sortable case when ordered by position ASC
|
||||
*/
|
||||
|
||||
$('body').on('mousedown', 'tbody.sortable [data-uniturl] td.placeholder', function () {
|
||||
const trParent = $(this).closest('tr');
|
||||
trParent.find('input:checkbox[name="bulk_action_selected_products[]"]').attr('checked', true);
|
||||
});
|
||||
|
||||
$('tbody.sortable', form).sortable({
|
||||
placeholder: 'placeholder',
|
||||
update(event, ui) {
|
||||
const positionSpan = $('span.position', ui.item)[0];
|
||||
$(positionSpan).css('color', 'red');
|
||||
bulkProductEdition(event, 'sort');
|
||||
},
|
||||
});
|
||||
|
||||
/*
|
||||
* Form submit pre action
|
||||
*/
|
||||
form.submit(function (e) {
|
||||
e.preventDefault();
|
||||
$('#filter_column_id_product', form).val($('#filter_column_id_product', form).attr('sql'));
|
||||
$('#filter_column_price', form).val($('#filter_column_price', form).attr('sql'));
|
||||
$('#filter_column_sav_quantity', form).val($('#filter_column_sav_quantity', form).attr('sql'));
|
||||
productCatalogFilterChanged = false;
|
||||
this.submit();
|
||||
return false;
|
||||
});
|
||||
|
||||
/*
|
||||
* Send to SQL manager button on modal
|
||||
*/
|
||||
$('#catalog_sql_query_modal button[value="sql_manager"]').on('click', () => {
|
||||
sendLastSqlQuery(createSqlQueryName());
|
||||
});
|
||||
|
||||
updateBulkMenu();
|
||||
updateFilterMenu();
|
||||
|
||||
/** create keyboard event for save & new */
|
||||
jwerty.key('ctrl+P', (e) => {
|
||||
e.preventDefault();
|
||||
const url = $('form#product_catalog_list').attr('newproducturl');
|
||||
window.location.href = url;
|
||||
});
|
||||
});
|
||||
|
||||
function productOrderTable(orderBy, orderWay) {
|
||||
const form = $('form#product_catalog_list');
|
||||
const url = form.attr('orderingurl').replace(/name/, orderBy).replace(/asc/, orderWay);
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
function productOrderPrioritiesTable() {
|
||||
window.location.href = $('form#product_catalog_list').attr('orderingurl');
|
||||
}
|
||||
|
||||
function updateBulkMenu() {
|
||||
// eslint-disable-next-line
|
||||
const selectedCount = $('form#product_catalog_list input:checked[name="bulk_action_selected_products[]"][disabled!="disabled"]').length;
|
||||
$('#product_bulk_menu').prop('disabled', (selectedCount === 0));
|
||||
}
|
||||
|
||||
let productCatalogFilterChanged = false;
|
||||
function updateFilterMenu() {
|
||||
const columnFilters = $('#product_catalog_list').find('tr.column-filters');
|
||||
let count = columnFilters.find('option:selected[value!=""]').length;
|
||||
columnFilters.find('input[type="text"][sql!=""][sql], input[type="text"]:visible').each(function () {
|
||||
if ($(this).val() !== '') {
|
||||
count += 1;
|
||||
}
|
||||
});
|
||||
const filtersNotUpdatedYet = (count === 0 && productCatalogFilterChanged === false);
|
||||
$('button[name="products_filter_submit"]').prop('disabled', filtersNotUpdatedYet);
|
||||
$('button[name="products_filter_reset"]').toggle(!filtersNotUpdatedYet);
|
||||
}
|
||||
|
||||
function productCategoryFilterReset(div) {
|
||||
$('#product_categories').categorytree('unselect');
|
||||
$('#product_catalog_list input[name="filter_category"]').val('');
|
||||
$('#product_catalog_list').submit();
|
||||
}
|
||||
|
||||
function productCategoryFilterExpand(div, btn) {
|
||||
$('#product_categories').categorytree('unfold');
|
||||
}
|
||||
|
||||
function productCategoryFilterCollapse(div, btn) {
|
||||
$('#product_categories').categorytree('fold');
|
||||
}
|
||||
|
||||
function categoryFilterButtons() {
|
||||
const catTree = $('#product_catalog_category_tree_filter');
|
||||
const catTreeSiblingDivs = $('#product_catalog_category_tree_filter ~ div');
|
||||
const catTreeList = catTree.find('ul ul');
|
||||
catTreeSiblingDivs.find('button[name="product_catalog_category_tree_filter_collapse"]')
|
||||
.toggle(!catTreeList.filter(':visible').length);
|
||||
catTreeSiblingDivs.find('button[name="product_catalog_category_tree_filter_expand"]')
|
||||
.toggle(!catTreeList.filter(':hidden').length);
|
||||
catTreeSiblingDivs.find('button[name="product_catalog_category_tree_filter_reset"]')
|
||||
.toggle(!catTree.find('ul input:checked').length);
|
||||
}
|
||||
|
||||
function productColumnFilterReset(tr) {
|
||||
$('input:text', tr).val('');
|
||||
$('select option:selected', tr).prop('selected', false);
|
||||
$('#filter_column_price', tr).attr('sql', '');
|
||||
$('#filter_column_sav_quantity', tr).attr('sql', '');
|
||||
$('#filter_column_id_product', tr).attr('sql', '');
|
||||
$('#product_catalog_list').submit();
|
||||
}
|
||||
|
||||
function bulkModalAction(allItems, postUrl, redirectUrl, action) {
|
||||
const itemsCount = allItems.length;
|
||||
let currentItemIdx = 0;
|
||||
|
||||
if (itemsCount < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetModal = $(`#catalog_${action}_modal`);
|
||||
targetModal.modal('show');
|
||||
|
||||
const details = targetModal.find(`#catalog_${action}_progression .progress-details-text`);
|
||||
const progressBar = targetModal.find(`#catalog_${action}_progression .progress-bar`);
|
||||
const failure = targetModal.find(`#catalog_${action}_failure`);
|
||||
|
||||
// re-init popup
|
||||
details.html(details.attr('default-value'));
|
||||
|
||||
progressBar.css('width', '0%');
|
||||
progressBar.find('span').html('');
|
||||
progressBar.removeClass('progress-bar-danger');
|
||||
progressBar.addClass('progress-bar-success');
|
||||
|
||||
failure.hide();
|
||||
|
||||
// call in ajax. Recursive with inner function
|
||||
const bulkCall = function (items, successCallback, errorCallback) {
|
||||
if (items.length === 0) {
|
||||
return;
|
||||
}
|
||||
const item0 = $(items.shift()).val();
|
||||
currentItemIdx += 1;
|
||||
|
||||
details.html(`${details.attr('default-value').replace(/\.\.\./, '')} (#${item0})`);
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: postUrl,
|
||||
data: {bulk_action_selected_products: [item0]},
|
||||
success(data, status) {
|
||||
// eslint-disable-next-line
|
||||
progressBar.css('width', `${currentItemIdx * 100 / itemsCount}%`);
|
||||
progressBar.find('span').html(`${currentItemIdx} / ${itemsCount}`);
|
||||
|
||||
if (items.length > 0) {
|
||||
bulkCall(items, successCallback, errorCallback);
|
||||
} else {
|
||||
successCallback();
|
||||
}
|
||||
},
|
||||
error: errorCallback,
|
||||
dataType: 'json',
|
||||
});
|
||||
};
|
||||
|
||||
bulkCall(allItems.toArray(), () => {
|
||||
window.location.href = redirectUrl;
|
||||
}, () => {
|
||||
progressBar.removeClass('progress-bar-success');
|
||||
progressBar.addClass('progress-bar-danger');
|
||||
failure.show();
|
||||
window.location.href = redirectUrl;
|
||||
});
|
||||
}
|
||||
|
||||
function bulkProductAction(element, action) {
|
||||
const form = $('#product_catalog_list');
|
||||
let postUrl = '';
|
||||
let redirectUrl = '';
|
||||
let urlHandler = null;
|
||||
|
||||
const items = $('input:checked[name="bulk_action_selected_products[]"]', form);
|
||||
|
||||
if (items.length === 0) {
|
||||
return false;
|
||||
}
|
||||
urlHandler = $(element).closest('[bulkurl]');
|
||||
|
||||
switch (action) {
|
||||
case 'delete_all':
|
||||
postUrl = urlHandler.attr('bulkurl').replace(/activate_all/, action);
|
||||
redirectUrl = urlHandler.attr('redirecturl');
|
||||
|
||||
// Confirmation popup and callback...
|
||||
$('#catalog_deletion_modal').modal('show');
|
||||
$('#catalog_deletion_modal button[value="confirm"]').off('click');
|
||||
$('#catalog_deletion_modal button[value="confirm"]').on('click', () => {
|
||||
$('#catalog_deletion_modal').modal('hide');
|
||||
|
||||
return bulkModalAction(items, postUrl, redirectUrl, action);
|
||||
});
|
||||
|
||||
return true; // No break, but RETURN, to avoid code after switch block :)
|
||||
|
||||
case 'activate_all':
|
||||
postUrl = urlHandler.attr('bulkurl');
|
||||
redirectUrl = urlHandler.attr('redirecturl');
|
||||
|
||||
return bulkModalAction(items, postUrl, redirectUrl, action);
|
||||
|
||||
break;
|
||||
|
||||
case 'deactivate_all':
|
||||
postUrl = urlHandler.attr('bulkurl').replace(/activate_all/, action);
|
||||
redirectUrl = urlHandler.attr('redirecturl');
|
||||
|
||||
return bulkModalAction(items, postUrl, redirectUrl, action);
|
||||
|
||||
break;
|
||||
|
||||
case 'duplicate_all':
|
||||
postUrl = urlHandler.attr('bulkurl').replace(/activate_all/, action);
|
||||
redirectUrl = urlHandler.attr('redirecturl');
|
||||
|
||||
return bulkModalAction(items, postUrl, redirectUrl, action);
|
||||
|
||||
break;
|
||||
|
||||
// this case will brings to the next page
|
||||
case 'edition_next':
|
||||
redirectUrl = $(element).closest('[massediturl]').attr('redirecturlnextpage');
|
||||
// no break !
|
||||
|
||||
// this case will post inline edition command
|
||||
// eslint-disable-next-line
|
||||
case 'edition':
|
||||
// eslint-disable-next-line
|
||||
let editionAction;
|
||||
// eslint-disable-next-line
|
||||
const bulkEditionSelector = '#bulk_edition_toolbar input:submit';
|
||||
|
||||
if ($(bulkEditionSelector).length > 0) {
|
||||
editionAction = $(bulkEditionSelector).attr('editionaction');
|
||||
} else {
|
||||
editionAction = 'sort';
|
||||
}
|
||||
|
||||
urlHandler = $('[massediturl]');
|
||||
postUrl = urlHandler.attr('massediturl').replace(/sort/, editionAction);
|
||||
if (redirectUrl === '') {
|
||||
redirectUrl = urlHandler.attr('redirecturl');
|
||||
}
|
||||
break;
|
||||
|
||||
// unknown cases...
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (postUrl !== '' && redirectUrl !== '') {
|
||||
// save action URL for redirection and update to post to bulk action instead
|
||||
// using form action URL allow to get route attributes and stay on the same page & ordering.
|
||||
const redirectionInput = $('<input>')
|
||||
.attr('type', 'hidden')
|
||||
.attr('name', 'redirect_url').val(redirectUrl);
|
||||
form.append($(redirectionInput));
|
||||
form.attr('action', postUrl);
|
||||
form.submit();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function unitProductAction(element, action) {
|
||||
const form = $('form#product_catalog_list');
|
||||
|
||||
// save action URL for redirection and update to post to bulk action instead
|
||||
// using form action URL allow to get route attributes and stay on the same page & ordering.
|
||||
const urlHandler = $(element).closest('[data-uniturl]');
|
||||
const redirectUrlHandler = $(element).closest('[redirecturl]');
|
||||
const redirectionInput = $('<input>')
|
||||
.attr('type', 'hidden')
|
||||
.attr('name', 'redirect_url').val(redirectUrlHandler.attr('redirecturl'));
|
||||
|
||||
// eslint-disable-next-line
|
||||
switch (action) {
|
||||
case 'delete':
|
||||
// Confirmation popup and callback...
|
||||
$('#catalog_deletion_modal').modal('show');
|
||||
$('#catalog_deletion_modal button[value="confirm"]').off('click');
|
||||
$('#catalog_deletion_modal button[value="confirm"]').on('click', () => {
|
||||
form.append($(redirectionInput));
|
||||
const url = urlHandler.attr('data-uniturl').replace(/duplicate/, action);
|
||||
form.attr('action', url);
|
||||
form.submit();
|
||||
|
||||
$('#catalog_deletion_modal').modal('hide');
|
||||
});
|
||||
return;
|
||||
// Other cases, nothing to do, continue.
|
||||
// default:
|
||||
}
|
||||
|
||||
form.append($(redirectionInput));
|
||||
const url = urlHandler.attr('data-uniturl').replace(/duplicate/, action);
|
||||
form.attr('action', url);
|
||||
form.submit();
|
||||
}
|
||||
|
||||
function showBulkProductEdition(show) {
|
||||
// Paginator does not have a next page link : we are on the last page!
|
||||
if ($('a#pagination_next_url[href]').length === 0) {
|
||||
$('#bulk_edition_save_next').prop('disabled', true).removeClass('btn-primary');
|
||||
$('#bulk_edition_save_keep').attr('type', 'submit').addClass('btn-primary');
|
||||
}
|
||||
if (show) {
|
||||
$('#bulk_edition_toolbar').show();
|
||||
} else {
|
||||
$('#bulk_edition_toolbar').hide();
|
||||
}
|
||||
}
|
||||
|
||||
function bulkProductEdition(element, action) {
|
||||
const form = $('form#product_catalog_list');
|
||||
|
||||
// eslint-disable-next-line
|
||||
switch (action) {
|
||||
case 'sort':
|
||||
showBulkProductEdition(true);
|
||||
$('input#bulk_action_select_all, input:checkbox[name="bulk_action_selected_products[]"]', form)
|
||||
.prop('disabled', true);
|
||||
$('#bulk_edition_toolbar input:submit').attr('editionaction', action);
|
||||
break;
|
||||
case 'cancel':
|
||||
// quantity inputs
|
||||
$('td.product-sav-quantity', form).each(function () {
|
||||
$(this).html($(this).attr('productquantityvalue'));
|
||||
});
|
||||
|
||||
$('#bulk_edition_toolbar input:submit').removeAttr('editionaction');
|
||||
showBulkProductEdition(false);
|
||||
$('input#bulk_action_select_all, input:checkbox[name="bulk_action_selected_products[]"]', form)
|
||||
.prop('disabled', false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function showLastSqlQuery() {
|
||||
$('#catalog_sql_query_modal_content textarea[name="sql"]').val($('tbody[last_sql]').attr('last_sql'));
|
||||
$('#catalog_sql_query_modal').modal('show');
|
||||
}
|
||||
|
||||
function sendLastSqlQuery(name) {
|
||||
$('#catalog_sql_query_modal_content textarea[name="sql"]').val($('tbody[last_sql]').attr('last_sql'));
|
||||
$('#catalog_sql_query_modal_content input[name="name"]').val(name);
|
||||
$('#catalog_sql_query_modal_content').submit();
|
||||
}
|
||||
47
iadmin/themes/default/js/bundle/product/default-category.js
Normal file
47
iadmin/themes/default/js/bundle/product/default-category.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Default category management
|
||||
*/
|
||||
const defaultCategory = (function () {
|
||||
const defaultCategoryForm = $('#form_step1_id_category_default');
|
||||
|
||||
return {
|
||||
init() {
|
||||
// Populate category tree with the default category
|
||||
const defaultCategoryId = defaultCategoryForm.find('input:checked').val();
|
||||
productCategoriesTags.checkDefaultCategory(defaultCategoryId);
|
||||
|
||||
/** Hide the default form, if javascript disabled it will be visible and so we
|
||||
* still can select a default category using the form
|
||||
*/
|
||||
defaultCategoryForm.hide();
|
||||
},
|
||||
|
||||
/**
|
||||
* Check the radio bouton with the selected value
|
||||
*/
|
||||
check(value) {
|
||||
defaultCategoryForm.find(`input[value="${value}"]`).prop('checked', true);
|
||||
},
|
||||
|
||||
isChecked(value) {
|
||||
return defaultCategoryForm.find(`input[value="${value}"]`).is(':checked');
|
||||
},
|
||||
|
||||
/**
|
||||
* When the category selected as a default is unselected
|
||||
* The default category MUST be a selected category
|
||||
*/
|
||||
reset() {
|
||||
const firstInput = defaultCategoryForm.find('input:first-child');
|
||||
firstInput.prop('checked', true);
|
||||
const categoryId = firstInput.val();
|
||||
productCategoriesTags.checkDefaultCategory(categoryId);
|
||||
},
|
||||
};
|
||||
}());
|
||||
|
||||
window.defaultCategory = defaultCategory;
|
||||
|
||||
BOEvent.on('Product Default category Management started', () => {
|
||||
defaultCategory.init();
|
||||
}, 'Back office');
|
||||
2313
iadmin/themes/default/js/bundle/product/form.js
Normal file
2313
iadmin/themes/default/js/bundle/product/form.js
Normal file
File diff suppressed because it is too large
Load Diff
209
iadmin/themes/default/js/bundle/product/product-category-tags.js
Normal file
209
iadmin/themes/default/js/bundle/product/product-category-tags.js
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* Product categories Tags management
|
||||
*/
|
||||
const productCategoriesTags = (function () {
|
||||
const defaultCategoryForm = $('#form_step1_id_category_default');
|
||||
const categoriesForm = $('#form_step1_categories');
|
||||
const tagsContainer = $('#ps_categoryTags');
|
||||
|
||||
return {
|
||||
init() {
|
||||
selectedCategories = this.getTags();
|
||||
selectedCategories.forEach(this.createTag);
|
||||
|
||||
// add tags management
|
||||
this.manageTagsOnInput();
|
||||
this.manageTagsOnTags();
|
||||
|
||||
// add default category management
|
||||
this.checkDefaultCategory();
|
||||
|
||||
// add search box
|
||||
this.initSearchBox();
|
||||
},
|
||||
removeTag(categoryId) {
|
||||
$(`span[data-id^="${categoryId}"]`).parent().remove();
|
||||
|
||||
return true;
|
||||
},
|
||||
getTags() {
|
||||
const firstStepCategoriesForm = $('#form_step1_categories');
|
||||
const inputs = firstStepCategoriesForm.find('label > input[type=checkbox]:checked').toArray();
|
||||
|
||||
const tags = [];
|
||||
const that = this;
|
||||
inputs.forEach((input) => {
|
||||
const tree = that.getTree();
|
||||
const tag = {
|
||||
name: input.parentNode.innerText,
|
||||
id: input.value,
|
||||
};
|
||||
tree.forEach((_category) => {
|
||||
if (_category.id === tag.id) {
|
||||
tag.breadcrumb = _category.breadcrumb;
|
||||
}
|
||||
});
|
||||
|
||||
tags.push(tag);
|
||||
});
|
||||
|
||||
return tags;
|
||||
},
|
||||
manageTagsOnInput() {
|
||||
const firstStepCategoriesForm = $('#form_step1_categories');
|
||||
const that = this;
|
||||
firstStepCategoriesForm.on('change', 'input[type=checkbox]', function () {
|
||||
const input = $(this);
|
||||
|
||||
if (input.prop('checked') === false) {
|
||||
that.removeTag($(this).val());
|
||||
} else {
|
||||
const tag = {
|
||||
name: input.parent().text(),
|
||||
id: input.val(),
|
||||
breadcrumb: '',
|
||||
};
|
||||
|
||||
that.createTag(tag);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
},
|
||||
manageTagsOnTags() {
|
||||
const that = this;
|
||||
|
||||
tagsContainer.on('click', 'a.pstaggerClosingCross', function (event) {
|
||||
event.preventDefault();
|
||||
const id = $(this).data('id');
|
||||
that.removeTag(id);
|
||||
categoriesForm.find(`input[value="${id}"].category`).prop('checked', false);
|
||||
tagsContainer.focus();
|
||||
});
|
||||
|
||||
return true;
|
||||
},
|
||||
checkDefaultCategory(categoryId) {
|
||||
const firstStepCategoriesForm = $('#form_step1_categories');
|
||||
const selector = `input[value="${categoryId}"].default-category`;
|
||||
firstStepCategoriesForm.find(selector).prop('checked', true);
|
||||
},
|
||||
getTree() {
|
||||
const tree = JSON.parse($('#ps_categoryTree').html());
|
||||
|
||||
return tree;
|
||||
},
|
||||
createTag(category) {
|
||||
if (category.breadcrumb === '') {
|
||||
const tree = this.getTree();
|
||||
tree.forEach((_category) => {
|
||||
if (_category.id === category.id) {
|
||||
category.breadcrumb = _category.breadcrumb;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const isTagExist = tagsContainer.find(`span[data-id=${category.id}]`);
|
||||
|
||||
if (isTagExist.length === 0) {
|
||||
tagsContainer.append(`${'<span class="pstaggerTag">'
|
||||
+ '<span data-id="'}${category.id}" title="${category.breadcrumb}">${category.name}</span>`
|
||||
+ `<a class="pstaggerClosingCross" href="#" data-id="${category.id}">x</a>`
|
||||
+ '</span>');
|
||||
const optionId = `#form_step1_id_category_default_${category.id}`;
|
||||
|
||||
if ($(optionId).length === 0) {
|
||||
defaultCategoryForm.append(`${'<div class="radio">'
|
||||
+ '<label class="required">'
|
||||
// eslint-disable-next-line
|
||||
+ '<input type="radio"' + 'id="form_step1_id_category_default_'}${category.id}" name="form[step1][id_category_default]" required="required" value="${category.id}">${
|
||||
category.name}</label>`
|
||||
+ '</div>');
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
getNameFromBreadcrumb(name) {
|
||||
if (name.indexOf('>') !== -1) {
|
||||
return name.substring(name.lastIndexOf('>') + 4); // remove "> "
|
||||
}
|
||||
|
||||
return name;
|
||||
},
|
||||
initSearchBox() {
|
||||
const searchCategorySelector = '#ps-select-product-category';
|
||||
const searchBox = $(searchCategorySelector);
|
||||
const tree = this.getTree();
|
||||
const tags = [];
|
||||
const that = this;
|
||||
let searchResultMsg = '';
|
||||
tree.forEach((tagObject) => {
|
||||
tags.push({
|
||||
label: tagObject.breadcrumb,
|
||||
value: tagObject.id,
|
||||
});
|
||||
});
|
||||
|
||||
// eslint-disable-next-line
|
||||
searchBox.autocomplete({
|
||||
source: tags,
|
||||
minChars: 2,
|
||||
autoFill: true,
|
||||
max: 20,
|
||||
matchContains: true,
|
||||
mustMatch: false,
|
||||
scroll: false,
|
||||
focus(event, ui) {
|
||||
event.preventDefault();
|
||||
const $this = $(this);
|
||||
$this.val(that.getNameFromBreadcrumb(ui.item.label));
|
||||
searchResultMsg = $this.parent().find('[role=status]').text();
|
||||
},
|
||||
select(event, ui) {
|
||||
event.preventDefault();
|
||||
const {label} = ui.item;
|
||||
const categoryName = that.getNameFromBreadcrumb(label);
|
||||
const categoryId = ui.item.value;
|
||||
|
||||
that.createTag({
|
||||
name: categoryName,
|
||||
id: categoryId,
|
||||
breadcrumb: label,
|
||||
});
|
||||
const firstStepCategoriesForm = $('#form_step1_categories');
|
||||
firstStepCategoriesForm.find(`input[value="${categoryId}"].category`).prop('checked', true);
|
||||
$(this).val('');
|
||||
},
|
||||
}).data('ui-autocomplete')._renderItem = function (ul, item) {
|
||||
return $('<li>')
|
||||
.data('ui-autocomplete-item', item)
|
||||
.append(`<a>${item.label}</a>`)
|
||||
.appendTo(ul);
|
||||
};
|
||||
|
||||
searchBox.parent().find('[role=status]').on('DOMSubtreeModified', function () {
|
||||
const $this = $(this);
|
||||
|
||||
if ($.isNumeric($this.text()) && searchResultMsg !== '' && searchBox.val() !== '') {
|
||||
$this.text(searchResultMsg);
|
||||
}
|
||||
});
|
||||
|
||||
$('body').on('focusout', searchCategorySelector, (event) => {
|
||||
const $searchInput = $(event.currentTarget);
|
||||
|
||||
if ($searchInput.val().length === 0) {
|
||||
$searchInput.parent().find('[role=status]').text('');
|
||||
searchResultMsg = '';
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
}());
|
||||
|
||||
window.productCategoriesTags = productCategoriesTags;
|
||||
|
||||
BOEvent.on('Product Categories Management started', () => {
|
||||
productCategoriesTags.init();
|
||||
}, 'Back office');
|
||||
328
iadmin/themes/default/js/bundle/product/product-combinations.js
Normal file
328
iadmin/themes/default/js/bundle/product/product-combinations.js
Normal file
@@ -0,0 +1,328 @@
|
||||
/**
|
||||
* Function for removing bad characters from localization formating.
|
||||
*/
|
||||
function replaceBadLocaleCharacters() {
|
||||
// eslint-disable-next-line
|
||||
$.each($('input.attribute_wholesale_price, input.attribute_priceTE, input.attribute_priceTI, input.attribute_unity, input.attribute_weight'), function () {
|
||||
$(this).val($(this).val().replace('−', '-')); // replace U+002D with U+2212
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Combination management
|
||||
*/
|
||||
window.combinations = (function () {
|
||||
/**
|
||||
* Remove a combination
|
||||
* @param {object} elem - The clicked link
|
||||
*/
|
||||
function remove(elem) {
|
||||
const combinationElem = $(`#attribute_${elem.attr('data')}`);
|
||||
|
||||
// eslint-disable-next-line
|
||||
window.modalConfirmation.create(translate_javascripts['Are you sure you want to delete this item?'], null, {
|
||||
onContinue() {
|
||||
// We need this because there is a specific data="smthg" attribute so we can't use data() function
|
||||
const attributeId = elem.attr('data');
|
||||
$.ajax({
|
||||
type: 'DELETE',
|
||||
data: {'attribute-ids': [attributeId]},
|
||||
url: elem.attr('href'),
|
||||
beforeSend() {
|
||||
elem.attr('disabled', 'disabled');
|
||||
$('#create-combinations, #apply-on-combinations, #submit, .btn-submit').attr('disabled', 'disabled');
|
||||
},
|
||||
success(response) {
|
||||
refreshTotalCombinations(-1, 1);
|
||||
combinationElem.remove();
|
||||
showSuccessMessage(response.message);
|
||||
displayFieldsManager.refresh();
|
||||
},
|
||||
error(response) {
|
||||
showErrorMessage(jQuery.parseJSON(response.responseText).message);
|
||||
},
|
||||
complete() {
|
||||
elem.removeAttr('disabled');
|
||||
$('#create-combinations, #apply-on-combinations, #submit, .btn-submit').removeAttr('disabled');
|
||||
supplierCombinations.refresh();
|
||||
warehouseCombinations.refresh();
|
||||
if ($('.js-combinations-list .combination').length <= 0) {
|
||||
$('#combinations_thead').fadeOut();
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
}).show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update final price, regarding the impact on price in combinations table
|
||||
* @param {jQuery} tableRow - Table row that contains the combination
|
||||
*/
|
||||
function updateFinalPrice(tableRow) {
|
||||
if (!tableRow.is('tr')) {
|
||||
throw new Error('Structure of table has changed, this function needs to be updated.');
|
||||
}
|
||||
|
||||
// We need this because there is a specific data="smthg" attribute so we can't use data() function
|
||||
const attributeId = tableRow.attr('data');
|
||||
|
||||
// Get combination final price value from combination form
|
||||
const finalPrice = priceCalculation.getCombinationFinalPriceTaxExcludedById(attributeId);
|
||||
const finalPriceLabel = tableRow.find('.attribute-finalprice span.final-price');
|
||||
finalPriceLabel.html(finalPrice);
|
||||
|
||||
// Update ecotax preview (tax included)
|
||||
let combinationEcotaxTI = priceCalculation.getCombinationEcotaxTaxIncludedById(attributeId);
|
||||
|
||||
if (combinationEcotaxTI === 0) {
|
||||
combinationEcotaxTI = priceCalculation.getProductEcotaxTaxIncluded();
|
||||
}
|
||||
const ecoTaxLabel = tableRow.find('.attribute-finalprice span.attribute-ecotax');
|
||||
ecoTaxLabel.html(Number(ps_round(combinationEcotaxTI, 2)).toFixed(2)); // 2 digits for short
|
||||
const ecoTaxPreview = tableRow.find('.attribute-finalprice .attribute-ecotax-preview');
|
||||
ecoTaxPreview.toggleClass('d-none', Number(combinationEcotaxTI) === 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the form for a specific combination
|
||||
* @param {String} attributeId
|
||||
* @return {jQuery}
|
||||
*/
|
||||
function getCombinationForm(attributeId) {
|
||||
return $(`#combination_form_${attributeId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the row of a specific combination
|
||||
* @param {String} attributeId
|
||||
* @return {jQuery}
|
||||
*/
|
||||
function getCombinationRow(attributeId) {
|
||||
return $(`#accordion_combinations #attribute_${attributeId}`);
|
||||
}
|
||||
|
||||
return {
|
||||
init() {
|
||||
const showVariationsSelector = '#show_variations_selector input';
|
||||
const productTypeSelector = $('#form_step1_type_product');
|
||||
const combinationsListSelector = '#accordion_combinations .combination';
|
||||
let combinationsList = $(combinationsListSelector);
|
||||
|
||||
if (combinationsList.length > 0) {
|
||||
productTypeSelector.prop('disabled', true);
|
||||
}
|
||||
|
||||
$(document)
|
||||
// delete combination
|
||||
.on('click', '#accordion_combinations .delete', function (e) {
|
||||
e.preventDefault();
|
||||
remove($(this));
|
||||
})
|
||||
|
||||
// when typing a new quantity on the form, update it on the row
|
||||
.on('keyup', 'input[id^="combination"][id$="_attribute_quantity"]', function () {
|
||||
const attributeId = $(this).closest('.combination-form').attr('data');
|
||||
const input = getCombinationRow(attributeId).find('.attribute-quantity input');
|
||||
|
||||
input.val($(this).val());
|
||||
})
|
||||
|
||||
// when typing a new quantity on the row, update it on the form
|
||||
.on('keyup', '.attribute-quantity input', function () {
|
||||
const attributeId = $(this).closest('.combination').attr('data');
|
||||
const input = getCombinationForm(attributeId).find('input[id^="combination"][id$="_attribute_quantity"]');
|
||||
|
||||
input.val($(this).val());
|
||||
})
|
||||
|
||||
.on({
|
||||
// when typing a new impact on price on the form, update it on the row
|
||||
keyup() {
|
||||
const attributeId = $(this).closest('.combination-form').attr('data');
|
||||
const input = getCombinationRow(attributeId).find('.attribute-price input');
|
||||
|
||||
input.val($(this).val());
|
||||
},
|
||||
// when impact on price on the form is changed, update final price
|
||||
change() {
|
||||
const attributeId = $(this).closest('.combination-form').attr('data');
|
||||
const input = getCombinationRow(attributeId).find('.attribute-price input');
|
||||
|
||||
input.val($(this).val());
|
||||
|
||||
updateFinalPrice($(input.parents('tr')[0]));
|
||||
},
|
||||
}, 'input[id^="combination"][id$="_attribute_price"]')
|
||||
|
||||
.on({
|
||||
// when ecotax on the form is changed, update final price
|
||||
change() {
|
||||
const attributeId = $(this).closest('.combination-form').attr('data');
|
||||
const finalPriceLabel = getCombinationRow(attributeId).find('.attribute-finalprice span.final-price');
|
||||
|
||||
updateFinalPrice($(finalPriceLabel.parents('tr')[0]));
|
||||
},
|
||||
}, 'input[id^="combination"][id$="_attribute_ecotax"]')
|
||||
|
||||
// when price impact is changed on the row, update it on the form
|
||||
.on('change', '.attribute-price input', function () {
|
||||
const attributeId = $(this).closest('.combination').attr('data');
|
||||
const input = getCombinationForm(attributeId).find('input[id^="combination"][id$="_attribute_price"]');
|
||||
|
||||
input.val($(this).val());
|
||||
// Trigger keyup to update form final price
|
||||
input.trigger('keyup');
|
||||
|
||||
updateFinalPrice($(this).parent().parent().parent());
|
||||
})
|
||||
|
||||
// on change default attribute, update which combination is the new default
|
||||
.on('click', 'input.attribute-default', function () {
|
||||
const selectedCombination = $(this);
|
||||
const combinationRadioButtons = $('input.attribute-default');
|
||||
const attributeId = $(this).closest('.combination').attr('data');
|
||||
|
||||
combinationRadioButtons.each(function unselect() {
|
||||
const combination = $(this);
|
||||
|
||||
if (combination.data('id') !== selectedCombination.data('id')) {
|
||||
combination.prop('checked', false);
|
||||
}
|
||||
});
|
||||
|
||||
$('.attribute_default_checkbox').prop('checked', false);
|
||||
getCombinationForm(attributeId)
|
||||
.find('input[id^="combination"][id$="_attribute_default"]')
|
||||
.prop('checked', true);
|
||||
})
|
||||
|
||||
// Combinations fields display management
|
||||
.on('change', showVariationsSelector, function () {
|
||||
displayFieldsManager.refresh();
|
||||
combinationsList = $(combinationsListSelector);
|
||||
|
||||
if ($(this).val() === '0') {
|
||||
// if combination(s) exists, alert user for deleting it
|
||||
if (combinationsList.length > 0) {
|
||||
window.modalConfirmation.create(
|
||||
translate_javascripts['Are you sure to disable variations ? they will all be deleted'], null, {
|
||||
onCancel() {
|
||||
$('#show_variations_selector input[value="1"]').prop('checked', true);
|
||||
displayFieldsManager.refresh();
|
||||
},
|
||||
onContinue() {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
// eslint-disable-next-line
|
||||
url: $('#accordion_combinations').attr('data-action-delete-all').replace(/\/\d+(?=\?.*)?/, `/${$('#form_id_product').val()}`),
|
||||
success() {
|
||||
combinationsList.remove();
|
||||
displayFieldsManager.refresh();
|
||||
},
|
||||
error(response) {
|
||||
showErrorMessage(jQuery.parseJSON(response.responseText).message);
|
||||
},
|
||||
});
|
||||
// enable the top header selector
|
||||
// we want to use a "Simple product" without any combinations
|
||||
productTypeSelector.prop('disabled', false);
|
||||
},
|
||||
}).show();
|
||||
} else {
|
||||
// enable the top header selector if no combination(s) exists
|
||||
productTypeSelector.prop('disabled', false);
|
||||
}
|
||||
} else {
|
||||
// this means we have or we want to have combinations
|
||||
// disable the product type selector
|
||||
productTypeSelector.prop('disabled', true);
|
||||
}
|
||||
})
|
||||
|
||||
// open combination form
|
||||
.on('click', '#accordion_combinations .btn-open', function (e) {
|
||||
e.preventDefault();
|
||||
const contentElem = $($(this).attr('href'));
|
||||
|
||||
/** create combinations navigation */
|
||||
const navElem = contentElem.find('.nav');
|
||||
const idAttribute = contentElem.attr('data');
|
||||
const prevCombinationId = $(`#accordion_combinations tr[data="${idAttribute}"]`).prev().attr('data');
|
||||
const nextCombinationId = $(`#accordion_combinations tr[data="${idAttribute}"]`).next().attr('data');
|
||||
navElem.find('.prev, .next').hide();
|
||||
if (prevCombinationId) {
|
||||
navElem.find('.prev').attr('data', prevCombinationId).show();
|
||||
}
|
||||
if (nextCombinationId) {
|
||||
navElem.find('.next').attr('data', nextCombinationId).show();
|
||||
}
|
||||
|
||||
/** init combination tax include price */
|
||||
replaceBadLocaleCharacters();
|
||||
priceCalculation.impactTaxInclude(contentElem.find('.attribute_priceTE'));
|
||||
priceCalculation.impactFinalPrice(contentElem.find('.attribute_priceTE'));
|
||||
|
||||
contentElem.insertBefore('#form-nav').removeClass('hide').show();
|
||||
|
||||
contentElem.find('.datepicker input[type="text"]').datetimepicker({
|
||||
locale: iso_user,
|
||||
format: 'YYYY-MM-DD',
|
||||
});
|
||||
|
||||
function countSelectedProducts() {
|
||||
return $(`#combination_form_${contentElem.attr('data')} .img-highlight`).length;
|
||||
}
|
||||
|
||||
const number = $(`#combination_form_${contentElem.attr('data')} .number-of-images`);
|
||||
// eslint-disable-next-line
|
||||
const allProductCombination = $(`#combination_form_${contentElem.attr('data')} .product-combination-image`).length;
|
||||
|
||||
number.text(`${countSelectedProducts()}/${allProductCombination}`);
|
||||
|
||||
$(document).on('click', '.tabs .product-combination-image', () => {
|
||||
number.text(`${countSelectedProducts()}/${allProductCombination}`);
|
||||
});
|
||||
|
||||
/** Add title on product's combination image */
|
||||
$(() => {
|
||||
$(`#combination_form_${contentElem.attr('data')}`).find('img').each(function () {
|
||||
title = $(this).attr('src').split('/').pop();
|
||||
$(this).attr('title', title);
|
||||
});
|
||||
});
|
||||
|
||||
$('#form-nav, #form_content').hide();
|
||||
})
|
||||
|
||||
// close combination form
|
||||
.on('click', '#form .combination-form .btn-back', function (e) {
|
||||
e.preventDefault();
|
||||
$(this).closest('.combination-form').hide();
|
||||
$('#form-nav, #form_content').show();
|
||||
})
|
||||
|
||||
// switch combination form
|
||||
.on('click', '#form .combination-form .nav a', function (e) {
|
||||
e.preventDefault();
|
||||
$('.combination-form').hide();
|
||||
$(`#accordion_combinations .combination[data="${$(this).attr('data')}"] .btn-open`).click();
|
||||
});
|
||||
},
|
||||
};
|
||||
}());
|
||||
|
||||
BOEvent.on('Product Combinations Management started', () => {
|
||||
combinations.init();
|
||||
}, 'Back office');
|
||||
|
||||
/**
|
||||
* Refresh bulk actions combination number after creating or deleting combinations
|
||||
*
|
||||
* @param {number} sign
|
||||
* @param {number} number
|
||||
*/
|
||||
window.refreshTotalCombinations = function (sign, number) {
|
||||
const $bulkCombinationsTotal = $('#js-bulk-combinations-total');
|
||||
const currentnumber = parseInt($bulkCombinationsTotal.text(), 10) + (sign * number);
|
||||
$bulkCombinationsTotal.text(currentnumber);
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Manufacturer management
|
||||
*/
|
||||
window.manufacturer = (function () {
|
||||
return {
|
||||
init() {
|
||||
const addButton = $('#add_brand_button');
|
||||
const resetButton = $('#reset_brand_product');
|
||||
const manufacturerContent = $('#manufacturer-content');
|
||||
const selectManufacturer = $('#form_step1_id_manufacturer');
|
||||
|
||||
/** Click event on the add button */
|
||||
addButton.on('click', (e) => {
|
||||
e.preventDefault();
|
||||
manufacturerContent.removeClass('hide');
|
||||
addButton.hide();
|
||||
});
|
||||
resetButton.on('click', (e) => {
|
||||
e.preventDefault();
|
||||
// eslint-disable-next-line
|
||||
modalConfirmation.create(translate_javascripts['Are you sure you want to delete this item?'], null, {
|
||||
onContinue() {
|
||||
manufacturerContent.addClass('hide');
|
||||
selectManufacturer.val('').trigger('change');
|
||||
addButton.show();
|
||||
},
|
||||
}).show();
|
||||
});
|
||||
},
|
||||
};
|
||||
}());
|
||||
|
||||
// eslint-disable-next-line
|
||||
BOEvent.on('Product Manufacturer Management started', () => {
|
||||
manufacturer.init();
|
||||
}, 'Back office');
|
||||
43
iadmin/themes/default/js/bundle/product/product-related.js
Normal file
43
iadmin/themes/default/js/bundle/product/product-related.js
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Related product management
|
||||
*/
|
||||
window.relatedProduct = (function () {
|
||||
return {
|
||||
init() {
|
||||
const addButton = $('#add-related-product-button');
|
||||
const resetButton = $('#reset_related_product');
|
||||
const relatedContent = $('#related-content');
|
||||
const productItems = $('#form_step1_related_products-data');
|
||||
const searchProductsBar = $('#form_step1_related_products');
|
||||
|
||||
addButton.on('click', (e) => {
|
||||
e.preventDefault();
|
||||
relatedContent.removeClass('hide');
|
||||
addButton.hide();
|
||||
});
|
||||
resetButton.on('click', (e) => {
|
||||
e.preventDefault();
|
||||
// eslint-disable-next-line
|
||||
modalConfirmation.create(translate_javascripts['Are you sure you want to delete this item?'], null, {
|
||||
onContinue: function onContinue() {
|
||||
const items = productItems.find('li').toArray();
|
||||
|
||||
items.forEach((item) => {
|
||||
console.log(item);
|
||||
item.remove();
|
||||
});
|
||||
searchProductsBar.val('');
|
||||
|
||||
relatedContent.addClass('hide');
|
||||
addButton.show();
|
||||
},
|
||||
}).show();
|
||||
});
|
||||
},
|
||||
};
|
||||
}());
|
||||
|
||||
// eslint-disable-next-line
|
||||
BOEvent.on('Product Related Management started', () => {
|
||||
relatedProduct.init();
|
||||
}, 'Back office');
|
||||
Reference in New Issue
Block a user