Initial commit

This commit is contained in:
2020-10-07 10:37:15 +02:00
commit ce5f440392
28157 changed files with 4429172 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
/**
* 2007-2019 PrestaShop and Contributors
*
* 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.txt.
* 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://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
function PerformancePage(addServerUrl, removeServerUrl, testServerUrl) {
this.addServerUrl = addServerUrl;
this.removeServerUrl = removeServerUrl;
this.testServerUrl = testServerUrl;
this.getAddServerUrl = function() {
return this.addServerUrl;
};
this.getRemoveServerlUrl = function() {
return this.removeServerUrl;
};
this.getTestServerUrl = function() {
return this.testServerUrl;
};
this.getFormValues = function() {
var serverIpInput = document.getElementById('form_add_memcache_server_memcache_ip');
var serverPortInput = document.getElementById('form_add_memcache_server_memcache_port');
var serverWeightInput = document.getElementById('form_add_memcache_server_memcache_weight');
return {
'server_ip': serverIpInput.value,
'server_port': serverPortInput.value,
'server_weight': serverWeightInput.value,
};
};
this.createRow = function(params) {
var serversTable = document.getElementById('servers-table');
var newRow = document.createElement('tr');
newRow.setAttribute('id', 'row_'+ params.id);
newRow.innerHTML =
'<td>'+ params.id +'</td>\n' +
'<td>'+ params.server_ip +'</td>\n' +
'<td>'+ params.server_port +'</td>\n' +
'<td>'+ params.server_weight +'</td>\n' +
'<td>\n' +
' <a class="btn btn-default" href="#" onclick="app.removeServer('+ params.id +');"><i class="material-icons">remove_circle</i> Remove</a>\n' +
'</td>\n';
serversTable.appendChild(newRow);
};
this.addServer = function() {
var app = this;
this.send(this.getAddServerUrl(), 'POST', this.getFormValues(), function(results) {
if (!results.hasOwnProperty('error')) {
app.createRow(results);
}
});
};
this.removeServer = function(serverId, removeMsg) {
var removeOk = confirm(removeMsg);
if (removeOk) {
this.send(this.getRemoveServerlUrl(), 'DELETE', {'server_id': serverId}, function(results) {
if (results === undefined) {
var row = document.getElementById('row_'+serverId);
row.parentNode.removeChild(row);
}
});
}
};
this.testServer = function() {
var app = this;
this.send(this.getTestServerUrl(), 'GET', this.getFormValues(), function(results) {
if (results.hasOwnProperty('error') || results.test === false) {
app.addClass('is-invalid');
return;
}
app.addClass('is-valid');
});
};
this.addClass = function(className) {
var serverFormInputs = document.querySelectorAll('#server-form input[type=text]');
for (var i = 0; i < serverFormInputs.length; i++) {
serverFormInputs[i].className = 'form-control '+ className;
}
}
/* global $ */
this.send = function(url, method, params, callback) {
return $.ajax({
url: url,
method: method,
data: params
}).done(callback);
};
}

View File

@@ -0,0 +1,104 @@
/**
* 2007-2019 PrestaShop and Contributors
*
* 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.txt.
* 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://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
var PerformancePageUI = {
displaySmartyCache: function() {
var CACHE_ENABLED = '1';
var smartyCacheSelected = document.querySelector('input[name="form[smarty][cache]"]:checked');
var smartyCacheOptions = document.querySelectorAll('.smarty-cache-option');
if (smartyCacheSelected && smartyCacheSelected.value === CACHE_ENABLED) {
for(var i = 0; i < smartyCacheOptions.length; i++) {
smartyCacheOptions[i].classList.remove('d-none');
}
return;
}
for(var i = 0; i < smartyCacheOptions.length; i++) {
smartyCacheOptions[i].classList.add('d-none');
}
},
displayCacheSystems: function() {
var CACHE_ENABLED = '1';
var cacheEnabledInput = document.querySelector('input[name="form[caching][use_cache]"]:checked');
var cachingElements = document.getElementsByClassName('memcache');
if(cacheEnabledInput.value === CACHE_ENABLED) {
for (var i = 0; i < cachingElements.length; i++) {
cachingElements[i].style.display = "block";
}
return;
}
for (var i = 0; i < cachingElements.length; i++) {
cachingElements[i].style.display = "none";
}
},
displayMemcacheServers: function() {
var CACHE_ENABLED = '1';
var cacheEnabledInput = document.querySelector('input[name="form[caching][use_cache]"]:checked');
var cacheSelected = document.querySelector('input[name="form[caching][caching_system]"]:checked');
var memcacheServersListBlock = document.getElementById('servers-list');
var newServerBtn = document.getElementById('new-server-btn');
var isMemcache = cacheSelected && (cacheSelected.value === "CacheMemcache" || cacheSelected.value === "CacheMemcached");
if (isMemcache && cacheEnabledInput.value === CACHE_ENABLED) {
memcacheServersListBlock.style.display = "block";
newServerBtn.style.display = "block";
return;
}
memcacheServersListBlock.style.display = "none";
newServerBtn.style.display = "none";
}
};
/**
* Animations on form values.
*/
window.addEventListener('load', function() {
PerformancePageUI.displaySmartyCache();
PerformancePageUI.displayCacheSystems();
PerformancePageUI.displayMemcacheServers();
});
var cacheSystemInputs = document.querySelectorAll('input[type=radio]');
var length = cacheSystemInputs.length;
while(length--) {
cacheSystemInputs[length].addEventListener('change', function(e) {
var name = e.target.getAttribute('name');
if ('form[caching][use_cache]' === name) {
return PerformancePageUI.displayCacheSystems();
}
if ('form[smarty][cache]' === name) {
return PerformancePageUI.displaySmartyCache();
}
if ('form[caching][caching_system]' === name) {
return PerformancePageUI.displayMemcacheServers();
}
});
}

View File

@@ -0,0 +1,89 @@
/**
* 2007-2019 PrestaShop and Contributors
*
* 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.txt.
* 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://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
(function ($) {
$.fn.categorytree = function (settings) {
var isMethodCall = (typeof settings === 'string'), // is this a method call like $().categorytree("unselect")
returnValue = this;
// if a method call execute the method on all selected instances
if (isMethodCall) {
switch (settings) {
case 'unselect':
this.find('.radio > label > input:radio').prop('checked', false);
// TODO: add a callback method feature?
break;
case 'unfold':
this.find('ul').show();
this.find('li').has('ul').removeClass('more').addClass('less');
break;
case 'fold':
this.find('ul ul').hide();
this.find('li').has('ul').removeClass('less').addClass('more');
break;
default:
throw 'Unknown method';
}
}
// initialize tree
else {
var clickHandler = function (event) {
var $ui = $(event.target);
if ($ui.attr('type') === 'radio' || $ui.attr('type') === 'checkbox') {
return;
} else {
event.stopPropagation();
}
if ($ui.next('ul').length === 0) {
$ui = $ui.parent();
}
$ui.next('ul').toggle();
if ($ui.next('ul').is(':visible')) {
$ui.parent('li').removeClass('more').addClass('less');
} else {
$ui.parent('li').removeClass('less').addClass('more');
}
return false;
};
this.find('li > ul').each(function (i, item) {
var $inputWrapper = $(item).prev('div');
$inputWrapper.on('click', clickHandler);
$inputWrapper.find('label').on('click', clickHandler);
if ($(item).is(':visible')) {
$(item).parent('li').removeClass('more').addClass('less');
} else {
$(item).parent('li').removeClass('less').addClass('more');
}
});
}
// return the jquery selection (or if it was a method call that returned a value - the returned value)
return returnValue;
};
})(jQuery);

View File

@@ -0,0 +1,86 @@
/**
* Default layout instanciation
*/
$(document).ready(function() {
var $this = $(this);
var $ajaxSpinner = $('.ajax-spinner');
$('[data-toggle="tooltip"]').tooltip();
rightSidebar.init();
/** spinner loading */
$this.ajaxStart(function () {
$ajaxSpinner.show();
});
$this.ajaxStop(function () {
$ajaxSpinner.hide();
});
$this.ajaxError(function () {
$ajaxSpinner.hide();
});
});
var rightSidebar = (function() {
return {
'init': function() {
$('.btn-sidebar').on('click', function initLoadQuickNav() {
$('div.right-sidebar-flex').removeClass('col-lg-12').addClass('col-lg-9');
/** Lazy load of sidebar */
var url = $(this).data('url');
var target = $(this).data('target');
if (url) {
rightSidebar.loadQuickNav(url,target);
}
});
$(document).on('hide.bs.sidebar', function(e) {
$('div.right-sidebar-flex').removeClass('col-lg-9').addClass('col-lg-12');
});
},
'loadQuickNav': function(url, target) {
/** Loads inner HTML in the sidebar container */
$(target).load(url, function() {
$(this).removeAttr('data-url');
$('ul.pagination > li > a[href]', this).on('click', function(e) {
e.preventDefault();
rightSidebar.navigationChange($(e.target).attr('href'), $(target));
});
$('ul.pagination > li > input[name="paginator_jump_page"]', this).on('keyup', function(e) {
if (e.which === 13) { // ENTER
e.preventDefault();
var val = parseInt($(e.target).val());
var limit = $(e.target).attr('pslimit');
var url = $(this).attr('psurl').replace(/999999/, (val-1)*limit);
rightSidebar.navigationChange(url, $(target));
}
});
});
},
'navigationChange': function(url, sidebar) {
rightSidebar.loadQuickNav(url, sidebar);
}
};
})();
/**
* BO Events Handler
*/
var BOEvent = {
on: function(eventName, callback, context) {
document.addEventListener(eventName, function(event) {
if (typeof context !== 'undefined') {
callback.call(context, event);
} else {
callback(event);
}
});
},
emitEvent: function(eventName, eventType) {
var _event = document.createEvent(eventType);
// true values stand for: can bubble, and is cancellable
_event.initEvent(eventName, true, true);
document.dispatchEvent(_event);
}
};

View File

@@ -0,0 +1,59 @@
/**
* modal confirmation management
*/
var modalConfirmation = (function() {
var modal = $('#confirmation_modal');
if(!modal) {
throw new Error('Modal confirmation is not available');
}
var actionsCallbacks = {
onCancel: function() {
console.log('modal canceled');
return;
},
onContinue: function() {
console.log('modal continued');
return;
}
};
modal.find('button.cancel').click(function() {
if (typeof actionsCallbacks.onCancel === 'function') {
actionsCallbacks.onCancel();
}
modalConfirmation.hide();
});
modal.find('button.continue').click(function() {
if (typeof actionsCallbacks.onContinue === 'function') {
actionsCallbacks.onContinue();
}
modalConfirmation.hide();
});
return {
'init': function init() {},
'create': function create(content, title, callbacks) {
if(title != null){
modal.find('.modal-title').html(title);
}
if(content != null){
modal.find('.modal-body').html(content);
}
actionsCallbacks = callbacks;
return this;
},
'show': function show() {
modal.modal('show');
},
'hide': function hide() {
modal.modal('hide');
}
};
})();
BOEvent.on("Modal confirmation started", function initModalConfirmationSystem() {
modalConfirmation.init();
}, "Back office");

View File

@@ -0,0 +1,53 @@
/**
* 2007-2019 PrestaShop and Contributors
*
* 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.txt.
* 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://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
$(function() {
var moduleImport = $("#module-import");
moduleImport.click(function() {
moduleImport.addClass("onclick", 250, validate);
});
function validate() {
setTimeout(function() {
moduleImport.removeClass("onclick");
moduleImport.addClass("validate", 450, callback);
}, 2250 );
}
function callback() {
setTimeout(function() {
moduleImport.removeClass("validate");
}, 1250 );
}
$('body').on('click', 'a.module-read-more-grid-btn, a.module-read-more-list-btn', function (event) {
event.preventDefault();
var urlCallModule = event.target.href;
var modulePoppin = $(event.target).data('target');
$.get(urlCallModule, function (data) {
$(modulePoppin).html(data);
$(modulePoppin).modal();
});
});
});

View File

@@ -0,0 +1,943 @@
$(document).ready(function() {
var controller = new AdminModuleController();
controller.init();
});
/**
* Module Admin Page Controller.
* @constructor
*/
var AdminModuleController = function() {
this.currentDisplay = '';
this.isCategoryGridDisplayed = false;
this.currentTagsList = [];
this.currentRefCategory = null;
this.currentRefStatus = null;
this.currentSorting = null;
this.baseAddonsUrl = 'https://addons.prestashop.com/';
this.pstaggerInput = null;
this.lastBulkAction = null;
this.isUploadStarted = false;
/**
* Loaded modules list.
* Containing the card and list display.
* @type {Array}
*/
this.modulesList = [];
this.addonsCardGrid = null;
this.addonsCardList = null;
// Selectors into vars to make it easier to change them while keeping same code logic
this.moduleItemGridSelector = '.module-item-grid';
this.moduleItemListSelector = '.module-item-list';
this.categorySelectorLabelSelector = '.module-category-selector-label';
this.categorySelector = '.module-category-selector';
this.categoryItemSelector = '.module-category-menu';
this.addonsLoginButtonSelector = '#addons_login_btn';
this.categoryResetBtnSelector = '.module-category-reset';
this.moduleInstallBtnSelector = 'input.module-install-btn';
this.moduleSortingDropdownSelector = '.module-sorting-author select';
this.categoryGridSelector = '#modules-categories-grid';
this.categoryGridItemSelector = '.module-category-item';
this.addonItemGridSelector = '.module-addons-item-grid';
this.addonItemListSelector = '.module-addons-item-list';
// Upgrade All selectors
this.upgradeAllSource = '.module_action_menu_upgrade_all';
this.upgradeAllTargets = '#modules-list-container-update .module_action_menu_upgrade:visible';
// Bulk action selectors
this.bulkActionDropDownSelector = '.module-bulk-actions select';
this.checkedBulkActionListSelector = '.module-checkbox-bulk-list input:checked';
this.checkedBulkActionGridSelector = '.module-checkbox-bulk-grid input:checked';
this.bulkActionCheckboxGridSelector = '.module-checkbox-bulk-grid';
this.bulkActionCheckboxListSelector = '.module-checkbox-bulk-list';
this.bulkActionCheckboxSelector = '#module-modal-bulk-checkbox';
this.bulkConfirmModalSelector = '#module-modal-bulk-confirm';
this.bulkConfirmModalActionNameSelector = '#module-modal-bulk-confirm-action-name';
this.bulkConfirmModalListSelector = '#module-modal-bulk-confirm-list';
this.bulkConfirmModalAckBtnSelector = '#module-modal-confirm-bulk-ack';
// Placeholders
this.placeholderGlobalSelector = '.module-placeholders-wrapper';
this.placeholderFailureGlobalSelector = '.module-placeholders-failure';
this.placeholderFailureMsgSelector = '.module-placeholders-failure-msg';
this.placeholderFailureRetryBtnSelector = '#module-placeholders-failure-retry';
// Module's statuses selectors
this.statusSelectorLabelSelector = '.module-status-selector-label';
this.statusItemSelector = '.module-status-menu';
this.statusResetBtnSelector = '.module-status-reset';
// Selectors for Module Import and Addons connect
this.addonsConnectModalBtnSelector = '#page-header-desc-configuration-addons_connect';
this.addonsLogoutModalBtnSelector = '#page-header-desc-configuration-addons_logout';
this.addonsImportModalBtnSelector = '#page-header-desc-configuration-add_module';
this.dropZoneModalSelector = '#module-modal-import';
this.dropZoneModalFooterSelector = '#module-modal-import .modal-footer';
this.dropZoneImportZoneSelector = '#importDropzone';
this.addonsConnectModalSelector = '#module-modal-addons-connect';
this.addonsLogoutModalSelector = '#module-modal-addons-logout';
this.addonsConnectForm = '#addons-connect-form';
this.moduleImportModalCloseBtn = '#module-modal-import-closing-cross';
this.moduleImportStartSelector = '.module-import-start';
this.moduleImportProcessingSelector = '.module-import-processing';
this.moduleImportSuccessSelector = '.module-import-success';
this.moduleImportSuccessConfigureBtnSelector = '.module-import-success-configure';
this.moduleImportFailureSelector = '.module-import-failure';
this.moduleImportFailureRetrySelector = '.module-import-failure-retry';
this.moduleImportFailureDetailsBtnSelector = '.module-import-failure-details-action';
this.moduleImportSelectFileManualSelector = '.module-import-start-select-manual';
this.moduleImportFailureMsgDetailsSelector = '.module-import-failure-details';
this.moduleImportConfirmSelector = '.module-import-confirm';
/**
* Initialize all listners and bind everything
* @method init
* @memberof AdminModule
*/
this.init = function () {
this.initBOEventRegistering();
this.loadVariables();
this.initSortingDisplaySwitch();
this.initSortingDropdown();
this.initSearchBlock();
this.initCategorySelect();
this.initCategoriesGrid();
this.initActionButtons();
this.initAddonsSearch();
this.initAddonsConnect();
this.initAddModuleAction();
this.initDropzone();
this.initPageChangeProtection();
this.initBulkActions();
this.initPlaceholderMechanism();
this.initFilterStatusDropdown();
this.fetchModulesList();
this.getNotificationsCount();
};
this.initFilterStatusDropdown = function() {
var self = this;
var body = $('body');
body.on('click', this.statusItemSelector, function () {
// Get data from li DOM input
self.currentRefStatus = parseInt($(this).attr('data-status-ref'));
var statusSelectedDisplayName = $(this).find('a:first').text();
// Change dropdown label to set it to the current status' displayname
$(self.statusSelectorLabelSelector).text(statusSelectedDisplayName);
$(self.statusResetBtnSelector).show();
// Do Search on categoryRef
self.updateModuleVisibility();
});
body.on('click', this.statusResetBtnSelector, function () {
var text = $(this).find('a').text();
$(self.statusSelectorLabelSelector).text(text);
$(this).hide();
self.currentRefStatus = null;
self.updateModuleVisibility();
});
};
this.initBOEventRegistering = function() {
BOEvent.on('Module Disabled', this.onModuleDisabled, this);
BOEvent.on('Module Uninstalled', this.updateTotalResults, this);
};
this.onModuleDisabled = function() {
var moduleItemSelector = this.getModuleItemSelector();
var self = this;
$('.modules-list').each(function() {
var totalForCurrentSelector = $(this).find(moduleItemSelector+':visible').length;
self.updateTotalResults(totalForCurrentSelector, $(this));
});
};
this.initPlaceholderMechanism = function() {
var self = this;
if ($(this.placeholderGlobalSelector).length) {
this.ajaxLoadPage();
}
// Retry loading mechanism
$('body').on('click', this.placeholderFailureRetryBtnSelector, function() {
$(self.placeholderFailureGlobalSelector).fadeOut();
$(self.placeholderGlobalSelector).fadeIn();
self.ajaxLoadPage();
});
};
this.ajaxLoadPage = function() {
var self = this;
$.ajax({
method: 'GET',
url: moduleURLs.catalogRefresh
}).done(function (response) {
if (response.status === true) {
if (typeof response.domElements === 'undefined') response.domElements = null;
if (typeof response.msg === 'undefined') response.msg = null;
var stylesheet = document.styleSheets[0];
var stylesheetRule = '{display: none}';
var moduleGlobalSelector = '.modules-list';
var moduleSortingSelector = '.module-sorting-menu';
var requiredSelectorCombination = moduleGlobalSelector + ', ' + moduleSortingSelector;
if (stylesheet.insertRule) {
stylesheet.insertRule(
requiredSelectorCombination +
stylesheetRule, stylesheet.cssRules.length
);
} else if (stylesheet.addRule) {
stylesheet.addRule(
requiredSelectorCombination,
stylesheetRule,
-1
);
}
$(self.placeholderGlobalSelector).fadeOut(800, function() {
$.each(response.domElements, function(index, element){
$(element.selector).append(element.content);
});
$(moduleGlobalSelector).fadeIn(800).css('display','flex');
$(moduleSortingSelector).fadeIn(800);
$('[data-toggle="popover"]').popover();
self.initCurrentDisplay();
self.fetchModulesList();
});
} else {
$(self.placeholderGlobalSelector).fadeOut(800, function() {
$(self.placeholderFailureMsgSelector).text(response.msg);
$(self.placeholderFailureGlobalSelector).fadeIn(800);
});
}
}).fail(function(response) {
$(self.placeholderGlobalSelector).fadeOut(800, function() {
$(self.placeholderFailureMsgSelector).text(response.statusText);
$(self.placeholderFailureGlobalSelector).fadeIn(800);
});
});
};
this.fetchModulesList = function() {
var self = this;
self.modulesList = [];
$(".modules-list").each(function() {
var container = $(this);
container.find(".module-item").each(function() {
var $this = $(this);
self.modulesList.push({
domObject: $this,
id: $this.attr('data-id'),
name: $this.attr('data-name').toLowerCase(),
scoring: parseFloat($this.attr('data-scoring')),
logo: $this.attr('data-logo'),
author: $this.attr('data-author').toLowerCase(),
version: $this.attr('data-version'),
description: $this.attr('data-description').toLowerCase(),
techName: $this.attr('data-tech-name').toLowerCase(),
childCategories: $this.attr('data-child-categories'),
categories: $this.attr('data-categories').toLowerCase(),
type: $this.attr('data-type'),
price: parseFloat($this.attr('data-price')),
active: parseInt($this.attr('data-active')),
access: $this.attr('data-last-access'),
display: $this.hasClass('module-item-list') ? 'list' : 'grid',
container: container
});
$this.remove();
});
});
self.addonsCardGrid = $(this.addonItemGridSelector);
self.addonsCardList = $(this.addonItemListSelector);
this.updateModuleVisibility();
$('body').trigger('moduleCatalogLoaded');
};
this.updateModuleVisibility = function() {
var self = this;
if (self.currentSorting) {
// Modules sorting
var order = 'asc';
var key = self.currentSorting;
if (key.split('-').length > 1) {
key = key.split('-')[0];
}
if (self.currentSorting.indexOf('-desc') != -1) {
order = 'desc';
}
function currentCompare(a, b) {
if (a[key] < b[key]) return -1;
if (a[key] > b[key]) return 1;
return 0;
}
self.modulesList.sort(currentCompare);
if (order == 'desc') {
self.modulesList.reverse();
}
}
$('.modules-list').html('');
// Modules visibility management
for (var i = 0; i < this.modulesList.length; i++) {
var currentModule = this.modulesList[i];
if (currentModule.display == this.currentDisplay) {
var isVisible = true;
if (this.currentRefCategory !== null) {
isVisible &= currentModule.categories === this.currentRefCategory;
}
if (self.currentRefStatus !== null) {
isVisible &= currentModule.active === this.currentRefStatus;
}
if (self.currentTagsList.length) {
var tagExists = false;
$.each(self.currentTagsList, function(index, value) {
value = value.toLowerCase();
tagExists |= (
currentModule.name.indexOf(value) != -1
|| currentModule.description.indexOf(value) != -1
|| currentModule.author.indexOf(value) != -1
|| currentModule.techName.indexOf(value) != -1
);
});
isVisible &= tagExists;
}
if (isVisible) {
currentModule.container.append(currentModule.domObject);
}
}
}
if (this.currentTagsList.length) {
if ('grid' === this.currentDisplay) {
$(".modules-list").append(this.addonsCardGrid);
} else {
$(".modules-list").append(this.addonsCardList);
}
}
this.updateTotalResults();
};
this.initPageChangeProtection = function() {
var self = this;
$(window).on('beforeunload', function() {
if (self.isUploadStarted === true) {
return "It seems some critical operation are running, are you sure you want to change page ? It might cause some unexepcted behaviors.";
}
});
};
this.initBulkActions = function() {
var self = this;
var body = $('body');
body.on('change', this.bulkActionDropDownSelector, function() {
if (0 === $(self.getBulkCheckboxesCheckedSelector()).length) {
$.growl.warning({message: translate_javascripts['Bulk Action - One module minimum']});
return;
}
self.lastBulkAction = $(this).find(':checked').attr('value');
var modulesListString = self.buildBulkActionModuleList();
var actionString = $(this).find(':checked').text().toLowerCase();
$(self.bulkConfirmModalListSelector).html(modulesListString);
$(self.bulkConfirmModalActionNameSelector).text(actionString);
if (self.lastBulkAction !== 'bulk-uninstall') {
$(self.bulkActionCheckboxSelector).hide();
}
$(self.bulkConfirmModalSelector).modal('show');
});
body.on('click', this.bulkConfirmModalAckBtnSelector, function(event) {
event.preventDefault();
event.stopPropagation();
$(self.bulkConfirmModalSelector).modal('hide');
self.doBulkAction(self.lastBulkAction);
});
};
this.buildBulkActionModuleList = function() {
var checkBoxesSelector = this.getBulkCheckboxesCheckedSelector();
var moduleItemSelector = this.getModuleItemSelector();
var alreadyDoneFlag = 0;
var htmlGenerated = '';
$(checkBoxesSelector).each(function() {
if (alreadyDoneFlag != 10) {
var currentElement = $(this).parents(moduleItemSelector);
htmlGenerated += '- ' + currentElement.attr('data-name') + '<br/>';
alreadyDoneFlag += 1;
} else {
// Break each
htmlGenerated += '- ...';
return false;
}
});
return htmlGenerated;
};
this.initAddonsConnect = function () {
var self = this;
// Make addons connect modal ready to be clicked
if ($(this.addonsConnectModalBtnSelector).attr('href') == '#') {
$(this.addonsConnectModalBtnSelector).attr('data-toggle', 'modal');
$(this.addonsConnectModalBtnSelector).attr('data-target', this.addonsConnectModalSelector);
}
if ($(this.addonsLogoutModalBtnSelector).attr('href') == '#') {
$(this.addonsLogoutModalBtnSelector).attr('data-toggle', 'modal');
$(this.addonsLogoutModalBtnSelector).attr('data-target', this.addonsLogoutModalSelector);
}
$('body').on('submit', this.addonsConnectForm, function (event) {
event.preventDefault();
event.stopPropagation();
$.ajax({
method: 'POST',
url: $(this).attr('action'),
dataType: 'json',
data: $(this).serialize(),
beforeSend: function() {
$(self.addonsLoginButtonSelector).show();
$("button.btn[type='submit']", self.addonsConnectForm).hide();
}
}).done(function (response) {
var responseCode = response.success;
var responseMsg = response.message;
if (responseCode === 1) {
location.reload();
} else {
$.growl.error({message: responseMsg});
$(self.addonsLoginButtonSelector).hide();
$("button.btn[type='submit']", self.addonsConnectForm).fadeIn();
}
});
});
};
this.initAddModuleAction = function () {
var addModuleButton = $(this.addonsImportModalBtnSelector);
addModuleButton.attr('data-toggle', 'modal');
addModuleButton.attr('data-target', this.dropZoneModalSelector);
};
this.initDropzone = function () {
var self = this;
var body = $('body');
var dropzone = $('.dropzone');
// Reset modal when click on Retry in case of failure
body.on('click', this.moduleImportFailureRetrySelector, function() {
$(self.moduleImportSuccessSelector + ', ' + self.moduleImportFailureSelector + ', ' + self.moduleImportProcessingSelector).fadeOut(function() {
// Added timeout for a better render of animation and avoid to have displayed at the same time
setTimeout(function() {
$(self.moduleImportStartSelector).fadeIn(function() {
$(self.moduleImportFailureMsgDetailsSelector).hide();
$(self.moduleImportSuccessConfigureBtnSelector).hide();
dropzone.removeAttr('style');
});
}, 550);
});
});
// Reinit modal on exit, but check if not already processing something
body.on('hidden.bs.modal', this.dropZoneModalSelector, function () {
$(self.moduleImportSuccessSelector + ', ' + self.moduleImportFailureSelector).hide();
$(self.moduleImportStartSelector).show();
dropzone.removeAttr('style');
$(self.moduleImportFailureMsgDetailsSelector).hide();
$(self.moduleImportSuccessConfigureBtnSelector).hide();
$(self.dropZoneModalFooterSelector).html('');
$(self.moduleImportConfirmSelector).hide();
});
// Change the way Dropzone.js lib handle file input trigger
body.on(
'click', '.dropzone:not('+this.moduleImportSelectFileManualSelector+', '+this.moduleImportSuccessConfigureBtnSelector+')',
function(event, manual_select) {
// if click comes from .module-import-start-select-manual, stop everything
if (typeof manual_select == "undefined") {
event.stopPropagation();
event.preventDefault();
}
}
);
body.on('click', this.moduleImportSelectFileManualSelector, function(event) {
event.stopPropagation();
event.preventDefault();
// Trigger click on hidden file input, and pass extra data to .dropzone click handler fro it to notice it comes from here
$('.dz-hidden-input').trigger('click', ["manual_select"]);
});
// Handle modal closure
body.on('click', this.moduleImportModalCloseBtn, function() {
if (self.isUploadStarted === true) {
// TODO: Display tooltip saying you can't escape at this stage
} else {
$(self.dropZoneModalSelector).modal('hide');
}
});
// Fix issue on click configure button
body.on('click', this.moduleImportSuccessConfigureBtnSelector, function(event) {
event.stopPropagation();
event.preventDefault();
window.location = $(this).attr('href');
});
// Open failure message details box
body.on('click', this.moduleImportFailureDetailsBtnSelector, function() {
$(self.moduleImportFailureMsgDetailsSelector).slideDown();
});
// @see: dropzone.js
var dropzoneOptions = {
url: moduleURLs.moduleImport,
acceptedFiles: '.zip, .tar',
// The name that will be used to transfer the file
paramName: 'file_uploaded',
maxFilesize: 50, // can't be greater than 50Mb because it's an addons limitation
uploadMultiple: false,
addRemoveLinks: true,
dictDefaultMessage: '',
hiddenInputContainer: self.dropZoneImportZoneSelector,
timeout:0, // add unlimited timeout. Otherwise dropzone timeout is 30 seconds and if a module is long to install, it is not possible to install the module.
addedfile: function() {
self.animateStartUpload();
},
processing: function () {
// Leave it empty since we don't require anything while processing upload
},
error: function (file, message) {
self.displayOnUploadError(message);
},
complete: function (file) {
if (file.status !== 'error') {
var responseObject = jQuery.parseJSON(file.xhr.response);
if (typeof responseObject.is_configurable === 'undefined') responseObject.is_configurable = null;
if (typeof responseObject.module_name === 'undefined') responseObject.module_name = null;
self.displayOnUploadDone(responseObject);
}
// State that we have finish the process to unlock some actions
self.isUploadStarted = false;
}
};
dropzone.dropzone($.extend(dropzoneOptions));
this.animateStartUpload = function() {
// State that we start module upload
self.isUploadStarted = true;
$(self.moduleImportStartSelector).hide(0);
dropzone.css('border', 'none');
$(self.moduleImportProcessingSelector).fadeIn();
};
this.animateEndUpload = function(callback) {
$(self.moduleImportProcessingSelector).finish().fadeOut(callback);
};
/**
* Method to call for upload modal, when the ajax call went well.
*
* @param object result containing the server response
*/
this.displayOnUploadDone = function(result) {
var self = this;
self.animateEndUpload(function() {
if (result.status === true) {
if (result.is_configurable === true) {
var configureLink = moduleURLs.configurationPage.replace('1', result.module_name);
$(self.moduleImportSuccessConfigureBtnSelector).attr('href', configureLink);
$(self.moduleImportSuccessConfigureBtnSelector).show();
}
$(self.moduleImportSuccessSelector).fadeIn();
} else if (typeof result.confirmation_subject !== 'undefined') {
self.displayPrestaTrustStep(result);
} else {
$(self.moduleImportFailureMsgDetailsSelector).html(result.msg);
$(self.moduleImportFailureSelector).fadeIn();
}
});
};
/**
* Method to call for upload modal, when the ajax call went wrong or when the action requested could not
* succeed for some reason.
*
* @param string message explaining the error.
*/
this.displayOnUploadError = function(message) {
self.animateEndUpload(function() {
$(self.moduleImportFailureMsgDetailsSelector).html(message);
$(self.moduleImportFailureSelector).fadeIn();
});
};
/**
* If PrestaTrust needs to be confirmed, we ask for the confirmation modal content and we display it in the
* currently displayed one. We also generate the ajax call to trigger once we confirm we want to install
* the module.
*
* @param Previous server response result
*/
this.displayPrestaTrustStep = function (result) {
var self = this;
var modal = module_card_controller.replacePrestaTrustPlaceholders(result);
var moduleName = result.module.attributes.name;
$(this.moduleImportConfirmSelector).html(modal.find('.modal-body').html()).fadeIn();
$(this.dropZoneModalFooterSelector).html(modal.find('.modal-footer').html()).fadeIn();
$(this.dropZoneModalFooterSelector).find(".pstrust-install").off('click').on('click', function() {
$(self.moduleImportConfirmSelector).hide();
$(self.dropZoneModalFooterSelector).html('');
self.animateStartUpload();
// Install ajax call
$.post(result.module.attributes.urls.install, { 'actionParams[confirmPrestaTrust]': "1"})
.done(function(data) {
self.displayOnUploadDone(data[moduleName]);
})
.fail(function(data) {
self.displayOnUploadError(data[moduleName]);
})
.always(function() {
self.isUploadStarted = false;
});
});
};
};
this.getBulkCheckboxesSelector = function () {
return this.currentDisplay == 'grid'
? this.bulkActionCheckboxGridSelector
: this.bulkActionCheckboxListSelector;
};
this.getBulkCheckboxesCheckedSelector = function () {
return this.currentDisplay == 'grid'
? this.checkedBulkActionGridSelector
: this.checkedBulkActionListSelector;
};
this.loadVariables = function () {
this.initCurrentDisplay();
};
this.getModuleItemSelector = function () {
return this.currentDisplay == 'grid'
? this.moduleItemGridSelector
: this.moduleItemListSelector;
};
/**
* Get the module notifications count and displays it as a badge on the notification tab
* @return void
*/
this.getNotificationsCount = function () {
var urlToCall = moduleURLs.notificationsCount;
$.getJSON(
urlToCall,
this.updateNotificationsCount
).fail(function() {
console.error('Could not retrieve module notifications count.');
});
};
this.updateNotificationsCount = function(badge) {
var destinationTabs = {
'to_configure': $("#subtab-AdminModulesNotifications"),
'to_update': $("#subtab-AdminModulesUpdates"),
};
for (var key in destinationTabs) {
if (destinationTabs[key].length === 0) {
continue;
}
destinationTabs[key].find('.notification-counter').text(badge[key]);
};
};
this.initAddonsSearch = function () {
var self = this;
$('body').on('click', this.addonItemGridSelector+', '+this.addonItemListSelector, function () {
var searchQuery = '';
if (self.currentTagsList.length) {
searchQuery = encodeURIComponent(self.currentTagsList.join(' '));
}
var hrefUrl = self.baseAddonsUrl+'search.php?search_query='+searchQuery;
window.open(hrefUrl, '_blank');
});
};
this.initCategoriesGrid = function () {
if (typeof refMenu === 'undefined') var refMenu = null;
var self = this;
$('body').on('click', this.categoryGridItemSelector, function (event) {
event.stopPropagation();
event.preventDefault();
var refCategory = $(this).attr('data-category-ref');
// In case we have some tags we need to reset it !
if (self.currentTagsList.length) {
self.pstaggerInput.resetTags(false);
self.currentTagsList = [];
}
var menuCategoryToTrigger = $(self.categoryItemSelector+'[data-category-ref="' + refCategory + '"]');
if (!menuCategoryToTrigger.length) {
console.warn('No category with ref ('+refMenu+') seems to exist!');
return false;
}
// Hide current category grid
if (self.isCategoryGridDisplayed === true) {
$(self.categoryGridSelector).fadeOut();
self.isCategoryGridDisplayed = false;
}
// Trigger click on right category
$(self.categoryItemSelector+'[data-category-ref="'+refCategory+'"]').click();
});
};
this.initCurrentDisplay = function() {
if (this.currentDisplay === '') {
this.currentDisplay = 'list';
} else {
this.currentDisplay = 'grid';
}
}
this.initSortingDropdown = function () {
var self = this;
self.currentSorting = $(this.moduleSortingDropdownSelector).find(':checked').attr('value');
$('body').on('change', this.moduleSortingDropdownSelector, function() {
self.currentSorting = $(this).find(':checked').attr('value');
self.updateModuleVisibility();
});
};
this.doBulkAction = function(requestedBulkAction) {
// This object is used to check if requested bulkAction is available and give proper
// url segment to be called for it
var forceDeletion = $('#force_bulk_deletion').prop('checked');
var bulkActionToUrl = {
'bulk-uninstall': 'uninstall',
'bulk-disable': 'disable',
'bulk-enable': 'enable',
'bulk-disable-mobile': 'disable_mobile',
'bulk-enable-mobile': 'enable_mobile',
'bulk-reset': 'reset'
};
// Note no grid selector used yet since we do not needed it at dev time
// Maybe useful to implement this kind of things later if intended to
// use this functionality elsewhere but "manage my module" section
if (typeof bulkActionToUrl[requestedBulkAction] === "undefined") {
$.growl.error({message: translate_javascripts['Bulk Action - Request not found'].replace('[1]', requestedBulkAction)});
return false;
}
// Loop over all checked bulk checkboxes
var bulkActionSelectedSelector = this.getBulkCheckboxesCheckedSelector();
if ($(bulkActionSelectedSelector).length > 0) {
var bulkModulesTechNames = [];
$(bulkActionSelectedSelector).each(function () {
var moduleTechName = $(this).attr('data-tech-name');
bulkModulesTechNames.push({
techName: moduleTechName,
actionMenuObj: $(this).parent().next()
});
});
$.each(bulkModulesTechNames, function (index, data) {
var actionMenuObj = data.actionMenuObj;
var moduleTechName = data.techName;
var urlActionSegment = bulkActionToUrl[requestedBulkAction];
if (typeof module_card_controller !== 'undefined') {
// We use jQuery to get the specific link for this action. If found, we send it.
var urlElement = $(module_card_controller.moduleActionMenuLinkSelector + urlActionSegment, actionMenuObj);
if (urlElement.length > 0) {
module_card_controller.requestToController(urlActionSegment, urlElement, forceDeletion);
} else {
$.growl.error({message: translate_javascripts["Bulk Action - Request not available for module"]
.replace('[1]', urlActionSegment)
.replace('[2]', moduleTechName)});
}
}
});
} else {
console.warn(translate_javascripts['Bulk Action - One module minimum']);
return false;
}
};
this.initActionButtons = function () {
$('body').on('click', this.moduleInstallBtnSelector, function(event) {
var $this = $(this);
var $next = $($this.next());
event.preventDefault();
$this.hide();
$next.show();
$.ajax({
url: $this.attr('data-url'),
dataType: 'json'
}).done(function () {
$next.fadeOut();
});
});
// "Upgrade All" button handler
var that = this;
$('body').on('click', this.upgradeAllSource, function(event) {
event.preventDefault();
$(that.upgradeAllTargets).click();
});
};
this.initCategorySelect = function () {
var self = this;
var body = $('body');
body.on('click', this.categoryItemSelector, function () {
// Get data from li DOM input
self.currentRefCategory = $(this).attr('data-category-ref').toLowerCase();
var categorySelectedDisplayName = $(this).attr('data-category-display-name');
// Change dropdown label to set it to the current category's displayname
$(self.categorySelectorLabelSelector).text(categorySelectedDisplayName);
$(self.categoryResetBtnSelector).show();
// Do Search on categoryRef
self.updateModuleVisibility();
});
body.on('click', this.categoryResetBtnSelector, function () {
var rawText = $(self.categorySelector).attr('aria-labelledby');
var upperFirstLetter = rawText.charAt(0).toUpperCase();
var removedFirstLetter = rawText.slice(1);
var originalText = upperFirstLetter + removedFirstLetter;
$(self.categorySelectorLabelSelector).text(originalText);
$(this).hide();
self.currentRefCategory = null;
self.updateModuleVisibility();
});
};
this.updateTotalResults = function() {
// If there are some shortlist: each shortlist count the modules on the next container.
var $shortLists = $('.module-short-list');
if ($shortLists.length > 0) {
$shortLists.each(function() {
var $this = $(this);
updateText(
$this.find('.module-search-result-wording'),
$this.next('.modules-list').find('.module-item').length
);
});
// If there is no shortlist: the wording directly update from the only module container.
} else {
var modulesCount = $('.modules-list').find('.module-item').length;
updateText(
$('.module-search-result-wording'),
modulesCount
);
$(this.addonItemGridSelector).toggle(modulesCount !== (this.modulesList.length/2));
$(this.addonItemListSelector).toggle(modulesCount !== (this.modulesList.length/2));
if (modulesCount === 0) {
$('.module-addons-search-link').attr(
'href',
this.baseAddonsUrl
+ 'search.php?search_query='
+ encodeURIComponent(this.currentTagsList.join(' '))
);
}
}
function updateText(element, value) {
var explodedText = element.text().split(' ');
explodedText[0] = value;
element.text(explodedText.join(' '));
}
};
this.initSearchBlock = function() {
var self = this;
this.pstaggerInput = $('#module-search-bar').pstagger({
onTagsChanged: function(tagList) {
self.currentTagsList = tagList;
self.updateModuleVisibility();
},
onResetTags: function() {
self.currentTagsList = [];
self.updateModuleVisibility();
},
inputPlaceholder: translate_javascripts['Search - placeholder'],
closingCross: true,
context: self,
});
$('body').on('click', '.module-addons-search-link', function(event) {
event.preventDefault();
event.stopPropagation();
var href = $(this).attr('href');
window.open(href, '_blank');
});
};
/**
* Initialize display switching between List or Grid
*/
this.initSortingDisplaySwitch = function() {
var self = this;
$('body').on('click', '.module-sort-switch', function() {
var switchTo = $(this).attr('data-switch');
var isAlreadyDisplayed = $(this).hasClass('active-display');
if (typeof switchTo !== 'undefined' && isAlreadyDisplayed === false) {
self.switchSortingDisplayTo(switchTo);
self.currentDisplay = switchTo;
}
});
};
this.switchSortingDisplayTo = function (switchTo) {
if (switchTo == 'grid' || switchTo == 'list') {
$('.module-sort-switch').removeClass('module-sort-active');
$('#module-sort-'+switchTo).addClass('module-sort-active');
this.currentDisplay = switchTo;
this.updateModuleVisibility();
} else {
console.error('Can\'t switch to undefined display property "' + switchTo + '"');
}
};
};

View File

@@ -0,0 +1,249 @@
var module_card_controller = {};
$(document).ready(function () {
module_card_controller = new AdminModuleCard();
module_card_controller.init();
});
/**
* AdminModule card Controller.
* @constructor
*/
var AdminModuleCard = function () {
/* Selectors for module action links (uninstall, reset, etc...) to add a confirm popin */
this.moduleActionMenuLinkSelector = 'button.module_action_menu_';
this.moduleActionMenuInstallLinkSelector = 'button.module_action_menu_install';
this.moduleActionMenuEnableLinkSelector = 'button.module_action_menu_enable';
this.moduleActionMenuUninstallLinkSelector = 'button.module_action_menu_uninstall';
this.moduleActionMenuDisableLinkSelector = 'button.module_action_menu_disable';
this.moduleActionMenuEnableMobileLinkSelector = 'button.module_action_menu_enable_mobile';
this.moduleActionMenuDisableMobileLinkSelector = 'button.module_action_menu_disable_mobile';
this.moduleActionMenuResetLinkSelector = 'button.module_action_menu_reset';
this.moduleActionMenuUpdateLinkSelector = 'button.module_action_menu_upgrade';
this.moduleItemListSelector = '.module-item-list';
this.moduleItemGridSelector = '.module-item-grid';
this.moduleItemActionsSelector = '.module-actions';
/* Selectors only for modal buttons */
this.moduleActionModalDisableLinkSelector = 'a.module_action_modal_disable';
this.moduleActionModalResetLinkSelector = 'a.module_action_modal_reset';
this.moduleActionModalUninstallLinkSelector = 'a.module_action_modal_uninstall';
this.forceDeletionOption = '#force_deletion';
/**
* Initialize all listeners and bind everything
* @method init
* @memberof AdminModuleCard
*/
this.init = function () {
this.initActionButtons();
};
this.getModuleItemSelector = function () {
if ($(this.moduleItemListSelector).length) {
return this.moduleItemListSelector;
} else {
return this.moduleItemGridSelector;
}
};
this.confirmAction = function(action, element) {
var modal = $('#' + $(element).data('confirm_modal'));
if (modal.length != 1) {
return true;
}
modal.first().modal('show');
return false; // do not allow a.href to reload the page. The confirm modal dialog will do it async if needed.
};
/**
* Update the content of a modal asking a confirmation for PrestaTrust and open it
*
* @param {array} result containing module data
* @return {void}
*/
this.confirmPrestaTrust = function confirmPrestaTrust(result) {
var that = this;
var modal = this.replacePrestaTrustPlaceholders(result);
modal.find(".pstrust-install").off('click').on('click', function() {
// Find related form, update it and submit it
var install_button = $(that.moduleActionMenuInstallLinkSelector, '.module-item[data-tech-name="' + result.module.attributes.name + '"]');
var form = install_button.parent("form");
$('<input>').attr({
type: 'hidden',
value: '1',
name: 'actionParams[confirmPrestaTrust]'
}).appendTo(form);
install_button.click();
modal.modal('hide');
});
modal.modal();
};
this.replacePrestaTrustPlaceholders = function replacePrestaTrustPlaceholders(result) {
var modal = $("#modal-prestatrust");
var module = result.module.attributes;
if (result.confirmation_subject !== 'PrestaTrust' || !modal.length) {
return;
}
var alertClass = module.prestatrust.status ? 'success' : 'warning';
if (module.prestatrust.check_list.property) {
modal.find("#pstrust-btn-property-ok").show();
modal.find("#pstrust-btn-property-nok").hide();
} else {
modal.find("#pstrust-btn-property-ok").hide();
modal.find("#pstrust-btn-property-nok").show();
modal.find("#pstrust-buy").attr("href", module.url).toggle(module.url !== null);
}
modal.find("#pstrust-img").attr({src: module.img, alt: module.name});
modal.find("#pstrust-name").text(module.displayName);
modal.find("#pstrust-author").text(module.author);
modal.find("#pstrust-label").attr("class", "text-" + alertClass).text(module.prestatrust.status ? 'OK' : 'KO');
modal.find("#pstrust-message").attr("class", "alert alert-"+alertClass);
modal.find("#pstrust-message > p").text(module.prestatrust.message);
return modal;
}
this.dispatchPreEvent = function (action, element) {
var event = jQuery.Event('module_card_action_event');
$(element).trigger(event, [action]);
if (event.isPropagationStopped() !== false || event.isImmediatePropagationStopped() !== false) {
return false; // if all handlers have not been called, then stop propagation of the click event.
}
return (event.result !== false); // explicit false must be set from handlers to stop propagation of the click event.
};
this.initActionButtons = function () {
var _this = this;
$(document).on('click', this.forceDeletionOption, function () {
var btn = $(_this.moduleActionModalUninstallLinkSelector, $("div.module-item-list[data-tech-name='" + $(this).attr("data-tech-name") + "']"));
if($(this).prop('checked') === true) {
btn.attr('data-deletion', 'true');
}else {
btn.removeAttr('data-deletion');
}
});
$(document).on('click', this.moduleActionMenuInstallLinkSelector, function () {
if ($("#modal-prestatrust").length) {
$("#modal-prestatrust").modal('hide');
}
return _this.dispatchPreEvent('install', this) && _this.confirmAction('install', this) && _this.requestToController('install', $(this));
});
$(document).on('click', this.moduleActionMenuEnableLinkSelector, function () {
return _this.dispatchPreEvent('enable', this) && _this.confirmAction('enable', this) && _this.requestToController('enable', $(this));
});
$(document).on('click', this.moduleActionMenuUninstallLinkSelector, function () {
return _this.dispatchPreEvent('uninstall', this) && _this.confirmAction('uninstall', this) && _this.requestToController('uninstall', $(this));
});
$(document).on('click', this.moduleActionMenuDisableLinkSelector, function () {
return _this.dispatchPreEvent('disable', this) && _this.confirmAction('disable', this) && _this.requestToController('disable', $(this));
});
$(document).on('click', this.moduleActionMenuEnableMobileLinkSelector, function () {
return _this.dispatchPreEvent('enable_mobile', this) && _this.confirmAction('enable_mobile', this) && _this.requestToController('enable_mobile', $(this));
});
$(document).on('click', this.moduleActionMenuDisableMobileLinkSelector, function () {
return _this.dispatchPreEvent('disable_mobile', this) && _this.confirmAction('disable_mobile', this) && _this.requestToController('disable_mobile', $(this));
});
$(document).on('click', this.moduleActionMenuResetLinkSelector, function () {
return _this.dispatchPreEvent('reset', this) && _this.confirmAction('reset', this) && _this.requestToController('reset', $(this));
});
$(document).on('click', this.moduleActionMenuUpdateLinkSelector, function () {
return _this.dispatchPreEvent('update', this) && _this.confirmAction('update', this) && _this.requestToController('update', $(this));
});
$(document).on('click', this.moduleActionModalDisableLinkSelector, function () {
return _this.requestToController('disable', $(_this.moduleActionMenuDisableLinkSelector, $("div.module-item-list[data-tech-name='" + $(this).attr("data-tech-name") + "']")));
});
$(document).on('click', this.moduleActionModalResetLinkSelector, function () {
return _this.requestToController('reset', $(_this.moduleActionMenuResetLinkSelector, $("div.module-item-list[data-tech-name='" + $(this).attr("data-tech-name") + "']")));
});
$(document).on('click', this.moduleActionModalUninstallLinkSelector, function (e) {
$(e.target).parents('.modal').on('hidden.bs.modal', function(event) {
return _this.requestToController(
'uninstall',
$(
_this.moduleActionMenuUninstallLinkSelector,
$("div.module-item-list[data-tech-name='" + $(e.target).attr("data-tech-name") + "']")
),
$(e.target).attr("data-deletion")
);
}.bind(e));
});
};
this.requestToController = function (action, element, forceDeletion) {
var _this = this;
var jqElementObj = element.closest(this.moduleItemActionsSelector);
var form = element.closest("form");
var spinnerObj = $("<button class=\"btn-primary-reverse onclick unbind spinner \"></button>");
var url = "//" + window.location.host + form.attr("action");
var actionParams = form.serializeArray();
if (forceDeletion === "true" || forceDeletion === true) {
actionParams.push({name: "actionParams[deletion]", value: true});
}
$.ajax({
url: url,
dataType: 'json',
method: 'POST',
data: actionParams,
beforeSend: function () {
jqElementObj.hide();
jqElementObj.after(spinnerObj);
}
}).done(function (result) {
if (typeof result === undefined) {
$.growl.error({message: "No answer received from server"});
} else {
var moduleTechName = Object.keys(result)[0];
if (result[moduleTechName].status === false) {
if (typeof result[moduleTechName].confirmation_subject !== 'undefined') {
_this.confirmPrestaTrust(result[moduleTechName]);
}
$.growl.error({message: result[moduleTechName].msg});
} else {
$.growl.notice({message: result[moduleTechName].msg});
var alteredSelector = null;
var mainElement = null;
if (action == "uninstall") {
jqElementObj.fadeOut(function() {
alteredSelector = _this.getModuleItemSelector().replace('.', '');
mainElement = jqElementObj.parents('.' + alteredSelector).first();
mainElement.remove();
});
BOEvent.emitEvent("Module Uninstalled", "CustomEvent");
} else if (action == "disable") {
alteredSelector = _this.getModuleItemSelector().replace('.', '');
mainElement = jqElementObj.parents('.' + alteredSelector).first();
mainElement.addClass(alteredSelector + '-isNotActive');
mainElement.attr('data-active', '0');
BOEvent.emitEvent("Module Disabled", "CustomEvent");
} else if (action == "enable") {
alteredSelector = _this.getModuleItemSelector().replace('.', '');
mainElement = jqElementObj.parents('.' + alteredSelector).first();
mainElement.removeClass(alteredSelector + '-isNotActive');
mainElement.attr('data-active', '1');
BOEvent.emitEvent("Module Enabled", "CustomEvent");
}
jqElementObj.replaceWith(result[moduleTechName].action_menu_html);
}
}
}).always(function () {
jqElementObj.fadeIn();
spinnerObj.remove();
});
return false;
};
};

View File

@@ -0,0 +1,78 @@
/**
* 2007-2019 PrestaShop and Contributors
*
* 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.txt.
* 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://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
$(document).ready(function() {
/*
* Link action on the select list in the navigator toolbar. When change occurs, the page is refreshed (location.href redirection)
*/
$('select[name="paginator_select_page_limit"]').change(function() {
var url = $(this).attr('psurl').replace(/_limit/, $('option:selected', this).val());
window.location.href = url;
return false;
});
/*
* Input field changes management
*/
function checkInputPage(eventOrigin) {
var e = eventOrigin || event;
var char = e.type === 'keypress' ? String.fromCharCode(e.keyCode || e.which) : (e.clipboardData || window.clipboardData).getData('Text');
if (/[^\d]/gi.test(char)) {
return false;
}
}
$('input[name="paginator_jump_page"]').each(function() {
this.onkeypress = checkInputPage;
this.onpaste = checkInputPage;
$(this).on('keyup', function(e) {
var val = parseInt($(e.target).val());
if (e.which === 13) { // ENTER
e.preventDefault();
if (parseInt(val) > 0) {
var limit = $(e.target).attr('pslimit');
var url = $(this).attr('psurl').replace(/999999/, (val-1)*limit);
window.location.href = url;
return false;
}
}
var max = parseInt($(e.target).attr('psmax'));
if (val > max) {
$(this).val(max);
return false;
}
});
$(this).on('blur', function(e) {
var val = parseInt($(e.target).val());
if (parseInt(val) > 0) {
var limit = $(e.target).attr('pslimit');
var url = $(this).attr('psurl').replace(/999999/, (val-1)*limit);
window.location.href = url;
return false;
}
});
});
});

View File

@@ -0,0 +1,272 @@
/**
* 2007-2019 PrestaShop and Contributors
*
* 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.txt.
* 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://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
(function ( $ ) {
var config = null;
var validateKeyCode = 13;
var tagsList = [];
var fullTagsString = null;
var pstaggerInput = null;
var defaultConfig = {
/* Global css config */
wrapperClassAdditional: '',
/* Tags part */
tagsWrapperClassAdditional: '',
tagClassAdditional: '',
closingCrossClassAdditionnal: '',
/* Tag Input part */
tagInputWrapperClassAdditional: '',
tagInputClassAdditional: '',
/* Global configuration */
delimiter: ' ',
inputPlaceholder: 'Add tag ...',
closingCross: true,
context: null,
clearAllBtn: false,
clearAllIconClassAdditional: '',
clearAllSpanClassAdditional: '',
/* Callbacks */
onTagsChanged: null,
onResetTags: null,
};
var immutableConfig = {
/* Global css config */
wrapperClass: 'pstaggerWrapper',
/* Tags part */
tagsWrapperClass: 'pstaggerTagsWrapper',
tagClass: 'pstaggerTag',
/* Tag Input part */
tagInputWrapperClass: 'pstaggerAddTagWrapper',
tagInputClass: 'pstaggerAddTagInput',
clearAllIconClass: '',
clearAllSpanClass: 'pstaggerResetTagsBtn',
closingCrossClass: 'pstaggerClosingCross',
};
var bindValidationInputEvent = function() {
// Validate input whenever validateKeyCode is pressed
pstaggerInput.keypress(function(event) {
if (event.keyCode == validateKeyCode) {
tagsList = [];
processInput();
}
});
// If focusout of input, display tagsWrapper if not empty or leave input as is
pstaggerInput.focusout(function(event){
// Necessarry to avoid race condition when focusout input because we want to reset :-)
if ($('.' + immutableConfig.clearAllSpanClass + ':hover').length) {
return false;
}
// Only redisplay tags on focusOut if there's something in tagsList
if (pstaggerInput.val().length) {
tagsList = [];
processInput();
}
});
};
var processInput = function() {
var fullTagsStringRaw = pstaggerInput.val();
var tagsListRaw = fullTagsStringRaw.split(config.delimiter);
// Check that's not an empty input
if (fullTagsStringRaw.length) {
// Loop over each tags we got this round
for (var key in tagsListRaw) {
var tagRaw = tagsListRaw[key];
// No empty values
if (tagRaw === '') {
continue;
}
// Add tag into persistent list
tagsList.push(tagRaw);
}
var spanTagsHtml = '';
// Create HTML dom from list of tags we have
for (key in tagsList) {
var tag = tagsList[key];
spanTagsHtml += formatSpanTag(tag);
}
// Delete previous if any, then add recreated html content
$('.' + immutableConfig.tagsWrapperClass).empty().prepend(spanTagsHtml).css('display', 'block');
// Hide input until user click on tagify_tags_wrapper
$('.' + immutableConfig.tagInputWrapperClass).css('display', 'none');
} else {
$('.' + immutableConfig.tagsWrapperClass).css('display', 'none');
$('.' + immutableConfig.tagInputWrapperClass).css('display', 'block');
pstaggerInput.focus();
}
// Call the callback ! (if one)
if (config.onTagsChanged !== null) {
config.onTagsChanged.call(config.context, tagsList);
}
};
var formatSpanTag = function(tag) {
var spanTag = '<span class="' + immutableConfig.tagClass + ' ' + config.tagClassAdditional+'">' +
'<span>' +
$('<div/>').text(tag).html() +
'</span>';
// Add closingCross if set to true
if (config.closingCross === true) {
spanTag += '<a class="' + immutableConfig.closingCrossClass + ' ' + config.closingCrossClassAdditionnal+'" href="#">x</a>';
}
spanTag += '</span>';
return spanTag;
};
var constructTagInputForm = function() {
// First hide native input
config.originalInput.css('display', 'none');
var addClearBtnHtml = '';
// If reset button required add it following user decription
if (config.clearAllBtn === true) {
addClearBtnHtml += '<span class="' + immutableConfig.clearAllSpanClass + ' ' + config.clearAllSpanClassAdditional +'">' +
'<i class="' + immutableConfig.clearAllIconClass + ' ' + config.clearAllIconClassAdditional +'">clear</i>' +
'</span>';
// Bind the click on the reset icon
bindResetTagsEvent();
}
// Add Tagify form after it
var formHtml = '<div class="' + immutableConfig.wrapperClass + ' ' + config.wrapperClassAdditional +'">' +
addClearBtnHtml +
'<div class="' + immutableConfig.tagsWrapperClass + ' ' + config.tagsWrapperClassAdditional +'"></div>' +
'<div class="' + immutableConfig.tagInputWrapperClass + ' ' + config.tagInputWrapperClassAdditional +'">' +
'<input class="' + immutableConfig.tagInputClass + ' ' + config.tagInputClassAdditional +'">' +
'</div>' +
'</div>';
// Insert form after the originalInput
config.originalInput.after(formHtml);
// Save tagify input in our object
pstaggerInput = $('.' + immutableConfig.tagInputClass);
// Add placeholder on tagify's input
pstaggerInput.attr('placeholder', config.inputPlaceholder);
return true;
};
var bindFocusInputEvent = function() {
// Bind click on tagsWrapper to switch and focus on input
$('.' + immutableConfig.tagsWrapperClass).on('click', function(event) {
var clickedElementClasses = event.target.className;
// Regexp to check if not clicked on closingCross to avoid focusing input if so
var checkClosingCrossRegex = new RegExp(immutableConfig.closingCrossClass, 'g');
var closingCrossClicked = clickedElementClasses.match(checkClosingCrossRegex);
if ($('.' + immutableConfig.tagInputWrapperClass).is(':hidden') && closingCrossClicked === null) {
$('.' + immutableConfig.tagsWrapperClass).css('display', 'none');
$('.' + immutableConfig.tagInputWrapperClass).css('display', 'block');
pstaggerInput.focus();
}
});
};
var bindResetTagsEvent = function() {
// Use delegate since we bind it before we insert the html in the DOM
var _this = this;
$(document).delegate('.' + immutableConfig.clearAllSpanClass, 'click', function(){
resetTags(true);
});
};
var resetTags = function(withCallback) {
// Empty tags list and tagify input
tagsList = [];
pstaggerInput.val('');
$('.' + immutableConfig.tagsWrapperClass).css('display', 'none');
$('.' + immutableConfig.tagInputWrapperClass).css('display', 'block');
pstaggerInput.focus();
// Empty existing Tags
$('.' + immutableConfig.tagClass).remove();
// Call the callback if one !
if (config.onResetTags !== null && withCallback === true) {
config.onResetTags.call(config.context);
}
}
var bindClosingCrossEvent = function() {
$(document).delegate('.' + immutableConfig.closingCrossClass, 'click', function(event){
var thisTagWrapper = $(this).parent();
var clickedTagIndex = thisTagWrapper.index();
// Iterate through tags to reconstruct new pstaggerInput value
var newInputValue = reconstructInputValFromRemovedTag(clickedTagIndex);
// Apply new input value
pstaggerInput.val(newInputValue);
thisTagWrapper.remove();
tagsList = [];
processInput();
});
};
var reconstructInputValFromRemovedTag = function(clickedTagIndex) {
var finalStr = '';
$('.' + immutableConfig.tagClass).each(function(index, value) {
// If this is the tag we want to remove then continue else add to return string val
if (clickedTagIndex == $(this).index()) {
// jQuery.each() continue;
return true;
}
// Add to return value
finalStr += ' ' + $(this).children().first().text();
});
return finalStr;
};
var getTagsListOccurencesCount = function() {
var obj = {};
for (var i = 0, j = tagsList.length; i < j; i++) {
obj[tagsList[i]] = (obj[tagsList[i]] || 0) + 1;
}
return obj;
};
var setConfig = function(givenConfig, originalObject) {
var finalConfig = {};
// Loop on each default values, check if one given by user, if so -> override default
for (var property in defaultConfig) {
if (givenConfig.hasOwnProperty(property)) {
finalConfig[property] = givenConfig[property];
} else {
finalConfig[property] = defaultConfig[property];
}
}
finalConfig.originalInput = originalObject;
return finalConfig;
};
// jQuery extends function
$.fn.pstagger = function(_config) {
config = setConfig(_config, this);
constructTagInputForm();
bindValidationInputEvent();
bindFocusInputEvent();
bindClosingCrossEvent();
return {
'resetTags': resetTags,
};
};
}(jQuery));

View File

@@ -0,0 +1,438 @@
/**
* 2007-2019 PrestaShop and Contributors
*
* 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.txt.
* 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://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2019 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
var $ = window.$;
$(document).ready(function() {
var 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', function() {
categoryFilterButtons();
});
categoryFilterButtons();
/*
* Click on a column header ordering icon to change orderBy / orderWay (location.href redirection)
*/
$('[psorderby][psorderway]', form).click(function() {
var orderBy = $(this).attr('psorderby');
var orderWay = $(this).attr('psorderway');
productOrderTable(orderBy, orderWay);
});
/*
* Checkboxes behavior with bulk actions
*/
$('input:checkbox[name="bulk_action_selected_products[]"]', form).change(function() {
updateBulkMenu();
});
/*
* Filter columns inputs behavior
*/
$('tr.column-filters input:text, tr.column-filters select', form).on('change input', function() {
productCatalogFilterChanged = true;
updateFilterMenu();
});
/*
* Sortable case when ordered by position ASC
*/
$("body").on("mousedown", "tbody.sortable [data-uniturl] td.placeholder", function () {
var trParent = $(this).closest('tr');
trParent.find('input:checkbox[name="bulk_action_selected_products[]"]').attr("checked", true);
});
$('tbody.sortable', form).sortable({
placeholder: 'placeholder',
update: function(event, ui) {
var 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', function() {
sendLastSqlQuery(createSqlQueryName());
});
updateBulkMenu();
updateFilterMenu();
/** create keyboard event for save & new */
jwerty.key('ctrl+P', function(e) {
e.preventDefault();
var url = $('form#product_catalog_list').attr('newproducturl');
window.location.href = url;
});
});
function productOrderTable(orderBy, orderWay) {
var form = $('form#product_catalog_list');
var url = form.attr('orderingurl').replace(/name/, orderBy).replace(/asc/, orderWay);
window.location.href = url;
}
function productOrderPrioritiesTable() {
window.location.href = $('form#product_catalog_list').attr('orderingurl');
}
function updateBulkMenu() {
var selectedCount = $('form#product_catalog_list input:checked[name="bulk_action_selected_products[]"][disabled!="disabled"]').length;
$('#product_bulk_menu').prop('disabled', (selectedCount === 0));
}
var productCatalogFilterChanged = false;
function updateFilterMenu() {
var columnFilters = $('#product_catalog_list').find('tr.column-filters');
var count = columnFilters.find('option:selected[value!=""]').length;
columnFilters.find('input[type="text"][sql!=""][sql], input[type="text"]:visible').each(function() {
if ($(this).val() !== '') {
count++;
}
});
var 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() {
var catTree = $('#product_catalog_category_tree_filter');
var catTreeSiblingDivs = $('#product_catalog_category_tree_filter ~ div');
var 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) {
var itemsCount = allItems.length;
var currentItemIdx = 0;
if (itemsCount < 1) {
return;
}
var targetModal = $('#catalog_' + action + '_modal');
targetModal.modal('show');
var details = targetModal.find('#catalog_' + action + '_progression .progress-details-text');
var progressBar = targetModal.find('#catalog_' + action + '_progression .progress-bar');
var 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
var bulkCall = function (items, successCallback, errorCallback) {
if (items.length === 0) {
return;
}
var item0 = $(items.shift()).val();
currentItemIdx++;
details.html(details.attr('default-value').replace(/\.\.\./, '') + ' (#' + item0 + ')');
$.ajax({
type: 'POST',
url: postUrl,
data: {bulk_action_selected_products: [item0]},
success: function (data, status) {
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(), function () {
window.location.href = redirectUrl;
}, function () {
progressBar.removeClass('progress-bar-success');
progressBar.addClass('progress-bar-danger');
failure.show();
window.location.href = redirectUrl;
});
}
function bulkProductAction(element, action) {
var form = $('#product_catalog_list');
var postUrl = '';
var redirectUrl = '';
var urlHandler = null;
var items = $('input:checked[name="bulk_action_selected_products[]"]', form);
if (items.length === 0) {
return false;
} else {
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', function () {
$('#catalog_deletion_modal').modal('hide');
return bulkModalAction(items, postUrl, redirectUrl, action);
});
return; // 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
case 'edition':
var editionAction;
var 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.
var 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) {
var 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.
var urlHandler = $(element).closest('[data-uniturl]');
var redirectUrlHandler = $(element).closest('[redirecturl]');
var redirectionInput = $('<input>')
.attr('type', 'hidden')
.attr('name', 'redirect_url').val(redirectUrlHandler.attr('redirecturl'));
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', function () {
form.append($(redirectionInput));
var 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));
var 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) {
var form = $('form#product_catalog_list');
switch (action) {
/*
case 'quantity_edition':
showBulkProductEdition(true);
$('input#bulk_action_select_all, input:checkbox[name="bulk_action_selected_products[]"]', form).prop('disabled', true);
i = 1;
$('td.product-sav-quantity', form).each(function() {
$quantity = $(this).attr('productquantityvalue');
$product_id = $(this).closest('tr[productid]').attr('productid');
$input = $('<input>').attr('type', 'text').attr('name', 'bulk_action_edit_quantity['+$product_id+']')
.attr('tabindex', i++)
.attr('onkeydown', 'if (event.keyCode == 13) return bulkProductAction(this, "edition_next"); if (event.keyCode == 27) return bulkProductEdition(this, "cancel");')
.val($quantity);
$(this).html($input);
});
$('#bulk_edition_toolbar input:submit').attr('tabindex', i++);
$('#bulk_edition_toolbar input:button').attr('tabindex', i++);
$('#bulk_edition_toolbar input:submit').attr('editionaction', action);
$('td.product-sav-quantity input', form).first().focus();
break;
*/
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();
}

View File

@@ -0,0 +1,44 @@
/**
* Default category management
*/
var defaultCategory = (function() {
var defaultCategoryForm = $('#form_step1_id_category_default');
return {
'init': function () {
/** Populate category tree with the default category **/
var 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': function(value) {
defaultCategoryForm.find('input[value="'+value+'"]').prop('checked', true);
},
'isChecked': function(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': function() {
var firstInput = defaultCategoryForm.find('input:first-child');
firstInput.prop('checked', true);
var categoryId = firstInput.val();
productCategoriesTags.checkDefaultCategory(categoryId);
}
};
})();
BOEvent.on("Product Default category Management started", function initDefaultCategoryManagement() {
defaultCategory.init();
}, "Back office");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,205 @@
/**
* Product categories Tags management
*/
var productCategoriesTags = (function () {
var defaultCategoryForm = $('#form_step1_id_category_default');
var categoriesForm = $('#form_step1_categories');
var tagsContainer = $('#ps_categoryTags');
return {
'init': function () {
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': function (categoryId) {
$('span[data-id^="' + categoryId + '"]').parent().remove();
return true;
},
'getTags': function () {
var categoriesForm = $('#form_step1_categories');
var inputs = categoriesForm.find('label > input[type=checkbox]:checked').toArray();
var tags = [];
var that = this;
inputs.forEach(function getLabels(input) {
var tree = that.getTree();
var tag = {
'name': input.parentNode.innerText,
'id': input.value,
};
tree.forEach(function getCategories(_category) {
if (_category.id == tag.id) {
tag.breadcrumb = _category.breadcrumb;
}
});
tags.push(tag);
});
return tags;
},
'manageTagsOnInput': function () {
var categoriesForm = $('#form_step1_categories');
var that = this;
categoriesForm.on('change', 'input[type=checkbox]', function (event) {
var input = $(this);
if (input.prop('checked') === false) {
that.removeTag($(this).val());
} else {
var tag = {
'name': input.parent().text(),
'id': input.val(),
'breadcrumb': ''
};
that.createTag(tag);
}
});
return true;
},
'manageTagsOnTags': function () {
var that = this;
tagsContainer.on('click', 'a.pstaggerClosingCross', function (event) {
event.preventDefault();
var id = $(this).data('id');
that.removeTag(id);
categoriesForm.find('input[value="' + id + '"].category').prop('checked', false);
tagsContainer.focus();
});
return true;
},
'checkDefaultCategory': function (categoryId) {
var categoriesForm = $('#form_step1_categories');
var selector = 'input[value="'+categoryId+'"].default-category';
categoriesForm.find(selector).prop('checked', true);
},
'getTree': function () {
var tree = JSON.parse($('#ps_categoryTree').html());
return tree;
},
'createTag': function (category) {
if (category.breadcrumb == '') {
var tree = this.getTree();
tree.forEach(function getCategories(_category) {
if (_category.id == category.id) {
category.breadcrumb = _category.breadcrumb;
}
});
}
var isTagExist = tagsContainer.find('span[data-id='+ category.id +']');
if(0 == isTagExist.length) {
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>')
;
var optionId = '#form_step1_id_category_default_' + category.id;
if (0 == $(optionId).length) {
defaultCategoryForm.append('<div class="radio">' +
'<label class="required">' +
'<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': function (name) {
if (name.indexOf('&gt;') !== -1) {
return name.substring(name.lastIndexOf('&gt') + 4); // remove "&gt; "
}
return name;
},
'initSearchBox': function () {
var searchCategorySelector = '#ps-select-product-category';
var searchBox = $(searchCategorySelector);
var tree = this.getTree();
var tags = [];
var that = this;
let searchResultMsg = '';
tree.forEach(function buildTags(tagObject){
tags.push({
label: tagObject.breadcrumb,
value: tagObject.id
});
});
searchBox.autocomplete({
source: tags,
minChars: 2,
autoFill: true,
max:20,
matchContains: true,
mustMatch:false,
scroll:false,
focus: function(event, ui) {
event.preventDefault();
let $this = $(this);
$this.val(that.getNameFromBreadcrumb(ui.item.label));
searchResultMsg = $this.parent().find('[role=status]').text();
},
select: function(event, ui) {
event.preventDefault();
var label = ui.item.label;
var categoryName = that.getNameFromBreadcrumb(label);
var categoryId = ui.item.value;
that.createTag({
'name': categoryName,
'id': categoryId,
'breadcrumb': label
});
var categoriesForm = $('#form_step1_categories');
categoriesForm.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 () {
let $this = $(this);
if ($.isNumeric($this.text()) && searchResultMsg !== '' && searchBox.val() !== '') {
$this.text(searchResultMsg);
}
});
$('body').on('focusout', searchCategorySelector, function (event) {
var $searchInput = $(event.currentTarget);
if (0 === $searchInput.val().length ) {
$searchInput.parent().find('[role=status]').text('');
searchResultMsg = '';
}
});
}
};
})();
BOEvent.on("Product Categories Management started", function initTagsManagement() {
productCategoriesTags.init();
}, "Back office");

View File

@@ -0,0 +1,294 @@
/**
* Combination management
*/
var combinations = (function() {
var id_product = $('#form_id_product').val();
/**
* Remove a combination
* @param {object} elem - The clicked link
*/
function remove(elem) {
var combinationElem = $('#attribute_' + elem.attr('data'));
modalConfirmation.create(translate_javascripts['Are you sure to delete this?'], null, {
onContinue: function() {
var attributeId = elem.attr('data');
$.ajax({
type: 'DELETE',
data: {'attribute-ids': [attributeId]},
url: elem.attr('href'),
beforeSend: function() {
elem.attr('disabled', 'disabled');
$('#create-combinations, #apply-on-combinations, #submit, .btn-submit').attr('disabled', 'disabled');
},
success: function(response) {
refreshTotalCombinations(-1, 1);
combinationElem.remove();
showSuccessMessage(response.message);
displayFieldsManager.refresh();
},
error: function(response) {
showErrorMessage(jQuery.parseJSON(response.responseText).message);
},
complete: function() {
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.');
}
var priceImpactInput = tableRow.find('.attribute_priceTE').first();
var finalPriceLabel = tableRow.find('.attribute-finalprice span');
var impactOnPrice = Tools.parseFloatFromString(priceImpactInput.val());
var previousImpactOnPrice = Tools.parseFloatFromString(priceImpactInput.attr('value'));
var currentFinalPrice = Tools.parseFloatFromString(finalPriceLabel.data('price'), true);
var finalPrice = currentFinalPrice - previousImpactOnPrice + impactOnPrice;
finalPriceLabel.html(Number(ps_round(finalPrice, 6)).toFixed(6));
}
/**
* 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': function() {
var showVariationsSelector = '#show_variations_selector input';
var productTypeSelector = $('#form_step1_type_product');
var combinationsListSelector = '#accordion_combinations .combination';
var 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() {
var attributeId = $(this).closest('.combination-form').attr('data');
var 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() {
var attributeId = $(this).closest('.combination').attr('data');
var 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': function () {
var attributeId = $(this).closest('.combination-form').attr('data');
var input = getCombinationRow(attributeId).find('.attribute-price input');
input.val($(this).val());
},
// when impact on price on the form is changed, update final price
'change': function () {
var attributeId = $(this).closest('.combination-form').attr('data');
var input = getCombinationRow(attributeId).find('.attribute-price input');
input.val($(this).val());
updateFinalPrice($(input.parents('tr')[0]));
}
}, 'input[id^="combination"][id$="_attribute_price"]')
// when price impact is changed on the row, update it on the form
.on('change', '.attribute-price input', function() {
var attributeId = $(this).closest('.combination').attr('data');
var input = getCombinationForm(attributeId).find('input[id^="combination"][id$="_attribute_price"]');
input.val($(this).val());
updateFinalPrice($(this).parent().parent().parent());
})
// on change default attribute, update which combination is the new default
.on('click', 'input.attribute-default', function() {
var selectedCombination = $(this);
var combinationRadioButtons = $('input.attribute-default');
var attributeId = $(this).closest('.combination').attr('data');
combinationRadioButtons.each(function unselect(index) {
var combination = $(this);
if (combination.data('id') !== selectedCombination.data('id')) {
combination.prop("checked", false);
}
});
$('.attribute_default_checkbox').removeAttr('checked');
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) {
modalConfirmation.create(translate_javascripts['Are you sure to disable variations ? they will all be deleted'], null, {
onCancel: function() {
$('#show_variations_selector input[value="1"]').prop('checked', true);
displayFieldsManager.refresh();
},
onContinue: function() {
$.ajax({
type: 'GET',
url: $('#accordion_combinations').attr('data-action-delete-all').replace(/\/\d+(?=\?.*)/, '/' + $('#form_id_product').val()),
success: function(response) {
combinationsList.remove();
displayFieldsManager.refresh();
},
error: function(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();
var contentElem = $($(this).attr('href'));
/** create combinations navigation */
var navElem = contentElem.find('.nav');
var id_attribute = contentElem.attr('data');
var prevCombinationId = $('#accordion_combinations tr[data="' + id_attribute + '"]').prev().attr('data');
var nextCombinationId = $('#accordion_combinations tr[data="' + id_attribute + '"]').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 */
priceCalculation.impactTaxInclude(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;
}
var number = $('#combination_form_' + contentElem.attr('data') + ' .number-of-images'),
allProductCombination = $('#combination_form_' + contentElem.attr('data') + ' .product-combination-image').length;
number.text(countSelectedProducts() + '/' + allProductCombination);
$(document).on('click','.tabs .product-combination-image', function () {
number.text(countSelectedProducts() + '/' + allProductCombination);
});
/** Add title on product's combination image */
$(function() {
$('#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", function initCombinationsManagement() {
combinations.init();
}, "Back office");
/**
* Refresh bulk actions combination number after creating or deleting combinations
*
* @param {number} sign
* @param {number} number
*/
var refreshTotalCombinations = function (sign, number) {
var $bulkCombinationsTotal = $('#js-bulk-combinations-total');
var currentnumber = parseInt($bulkCombinationsTotal.text()) + (sign * number);
$bulkCombinationsTotal.text(currentnumber);
}

View File

@@ -0,0 +1,34 @@
/**
* Manufacturer management
*/
var manufacturer = (function() {
return {
'init': function() {
var addButton = $('#add_brand_button');
var resetButton = $('#reset_brand_product');
var manufacturerContent = $('#manufacturer-content');
var selectManufacturer = $('#form_step1_id_manufacturer');
/** Click event on the add button */
addButton.on('click', function(e) {
e.preventDefault();
manufacturerContent.removeClass('hide');
addButton.hide();
});
resetButton.on('click', function(e) {
e.preventDefault();
modalConfirmation.create(translate_javascripts['Are you sure to delete this?'], null, {
onContinue: function(){
manufacturerContent.addClass('hide');
selectManufacturer.val('').trigger('change');
addButton.show();
}
}).show();
});
}
};
})();
BOEvent.on("Product Manufacturer Management started", function initManufacturerManagement() {
manufacturer.init();
}, "Back office");

View File

@@ -0,0 +1,42 @@
/**
* Related product management
*/
var relatedProduct = (function() {
return {
'init': function() {
var addButton = $('#add-related-product-button');
var resetButton = $('#reset_related_product');
var relatedContent = $('#related-content');
var productItems = $('#form_step1_related_products-data');
var searchProductsBar = $('#form_step1_related_products');
addButton.on('click', function(e) {
e.preventDefault();
relatedContent.removeClass('hide');
addButton.hide();
});
resetButton.on('click', function(e) {
e.preventDefault();
modalConfirmation.create(translate_javascripts['Are you sure to delete this?'], null, {
onContinue: function onContinue(){
var items = productItems.find('li').toArray();
items.forEach(function removeItem(item) {
console.log(item);
item.remove();
});
searchProductsBar.val('');
relatedContent.addClass('hide');
addButton.show();
}
}).show();
});
}
};
})();
BOEvent.on("Product Related Management started", function initRelatedProductManagement() {
relatedProduct.init();
}, "Back office");

View File

@@ -0,0 +1,148 @@
/* ========================================================================
* Bootstrap: sidebar.js v0.1
* ========================================================================
* Copyright 2011-2014 Asyraf Abdul Rahman
* Licensed under MIT
* ======================================================================== */
(function ($) {
'use strict';
// SIDEBAR PUBLIC CLASS DEFINITION
// ================================
var Sidebar = function (element, options) {
this.$element = $(element);
this.options = $.extend({}, Sidebar.DEFAULTS, options);
this.transitioning = null;
if (this.options.parent) {
this.$parent = $(this.options.parent);
}
if (this.options.toggle) {
this.toggle();
}
};
Sidebar.DEFAULTS = {
toggle: true
};
Sidebar.prototype.show = function () {
if (this.transitioning || this.$element.hasClass('sidebar-open')) {
return;
}
var startEvent = $.Event('show.bs.sidebar');
this.$element.trigger(startEvent);
if (startEvent.isDefaultPrevented()) {
return;
}
this.$element
.addClass('sidebar-open');
this.transitioning = 1;
var complete = function () {
this.transitioning = 0;
this.$element.trigger('shown.bs.sidebar');
};
if(!$.support.transition) {
return complete.call(this);
}
this.$element
.one($.support.transition.end, $.proxy(complete, this))
.emulateTransitionEnd(400);
};
Sidebar.prototype.hide = function () {
if (this.transitioning || !this.$element.hasClass('sidebar-open')) {
return;
}
var startEvent = $.Event('hide.bs.sidebar');
this.$element.trigger(startEvent);
if(startEvent.isDefaultPrevented()) {
return;
}
this.$element
.removeClass('sidebar-open');
this.transitioning = 1;
var complete = function () {
this.transitioning = 0;
this.$element
.trigger('hidden.bs.sidebar');
};
if (!$.support.transition) {
return complete.call(this);
}
this.$element
.one($.support.transition.end, $.proxy(complete, this))
.emulateTransitionEnd(400);
};
Sidebar.prototype.toggle = function () {
this[this.$element.hasClass('sidebar-open') ? 'hide' : 'show']();
};
var old = $.fn.sidebar;
$.fn.sidebar = function (option) {
return this.each(function (){
var $this = $(this);
var data = $this.data('bs.sidebar');
var options = $.extend({}, Sidebar.DEFAULTS, $this.data(), typeof options === 'object' && option);
if (!data && options.toggle && option === 'show') {
option = !option;
}
if (!data) {
$this.data('bs.sidebar', (data = new Sidebar(this, options)));
}
if (typeof option === 'string') {
data[option]();
}
});
};
$.fn.sidebar.Constructor = Sidebar;
$.fn.sidebar.noConflict = function () {
$.fn.sidebar = old;
return this;
};
$(document).on('click.bs.sidebar.data-api', '[data-toggle="sidebar"]', function (e) {
var $this = $(this), href;
var target = $this.attr('data-target') || e.preventDefault() || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '');
var $target = $(target);
var data = $target.data('bs.sidebar');
var option = data ? 'toggle' : $this.data();
$target.sidebar(option);
});
$('html').on('click.bs.sidebar.autohide', function(event){
var $this = $(event.target);
var isButtonOrSidebar = $this.is('.sidebar, [data-toggle="sidebar"]') || $this.parents('.sidebar, [data-toggle="sidebar"]').length;
if (isButtonOrSidebar) {
return;
} else {
var $target = $('.sidebar');
$target.each(function(i, trgt) {
var $trgt = $(trgt);
if($trgt.data('bs.sidebar') && $trgt.hasClass('sidebar-open')) {
$trgt.sidebar('hide');
}
});
}
});
})(jQuery);