first commit
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Responsible for connecting to addons marketplace.
|
||||
* Makes an addons connect request to the server, displays error messages if it fails.
|
||||
*/
|
||||
export default class AddonsConnector {
|
||||
constructor(
|
||||
addonsConnectFormSelector,
|
||||
loadingSpinnerSelector,
|
||||
) {
|
||||
this.addonsConnectFormSelector = addonsConnectFormSelector;
|
||||
this.$loadingSpinner = $(loadingSpinnerSelector);
|
||||
|
||||
this.initEvents();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize events related to connection to addons.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
initEvents() {
|
||||
$('body').on(
|
||||
'submit',
|
||||
this.addonsConnectFormSelector,
|
||||
(event) => {
|
||||
const $form = $(event.currentTarget);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
this.connect($form.attr('action'), $form.serialize());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do a POST request to connect to addons.
|
||||
*
|
||||
* @param {String} addonsConnectUrl
|
||||
* @param {Object} formData
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
connect(addonsConnectUrl, formData) {
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: addonsConnectUrl,
|
||||
dataType: 'json',
|
||||
data: formData,
|
||||
beforeSend: () => {
|
||||
this.$loadingSpinner.show();
|
||||
$('button.btn[type="submit"]', this.addonsConnectFormSelector).hide();
|
||||
},
|
||||
}).then((response) => {
|
||||
if (response.success === 1) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
$.growl.error({
|
||||
message: response.message,
|
||||
});
|
||||
|
||||
this.$loadingSpinner.hide();
|
||||
$('button.btn[type="submit"]', this.addonsConnectFormSelector).fadeIn();
|
||||
}
|
||||
}, () => {
|
||||
$.growl.error({
|
||||
message: $(this.addonsConnectFormSelector).data('error-message'),
|
||||
});
|
||||
|
||||
this.$loadingSpinner.hide();
|
||||
$('button.btn[type="submit"]', this.addonsConnectFormSelector).show();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
/**
|
||||
* This component is an overlay of typeahead it allows to have a single config input (since
|
||||
* typeahead weirdly uses two different configs). It also provides some default rendering
|
||||
* functions which are, of course, overridable.
|
||||
*/
|
||||
export default class AutoCompleteSearch {
|
||||
constructor($searchInput, config) {
|
||||
this.$searchInput = $searchInput;
|
||||
this.searchInputId = this.$searchInput.prop('id');
|
||||
|
||||
const inputConfig = config || {};
|
||||
// Merge default and input config
|
||||
this.config = {
|
||||
minLength: 2,
|
||||
highlight: true,
|
||||
cache: false,
|
||||
hint: false,
|
||||
...inputConfig,
|
||||
};
|
||||
|
||||
// Merge default and input dataSetConfig
|
||||
this.dataSetConfig = {
|
||||
display: 'name', // Which field of the object from the list is used for display (can be a string or a callback)
|
||||
value: 'id', // Which field of the object from the list is used for value (can be a string or a callback)
|
||||
limit: 20, // Limit the number of displayed suggestion
|
||||
dataLimit: 0, // How many elements can be selected max
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
onSelect(selectedItem, event) {
|
||||
return true;
|
||||
},
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
onClose(event) {
|
||||
},
|
||||
...inputConfig,
|
||||
};
|
||||
|
||||
// Merging object works fine on one level, but on two it erases sub elements even if not present, so
|
||||
// we handle templates separately, these are the default rendering functions which can be overridden
|
||||
const defaultTemplates = {
|
||||
// Be careful that your rendering function must return HTML node not pure text so always include the
|
||||
// content in a div at least
|
||||
suggestion: (item) => {
|
||||
let displaySuggestion = item;
|
||||
|
||||
if (typeof this.dataSetConfig.display === 'function') {
|
||||
this.dataSetConfig.display(item);
|
||||
} else if (Object.prototype.hasOwnProperty.call(item, this.dataSetConfig.display)) {
|
||||
displaySuggestion = item[this.dataSetConfig.display];
|
||||
}
|
||||
|
||||
return `<div class="px-2">${displaySuggestion}</div>`;
|
||||
},
|
||||
pending(query) {
|
||||
return `<div class="px-2">Searching for "${query.query}"</div>`;
|
||||
},
|
||||
notFound(query) {
|
||||
return `<div class="px-2">No results found for "${query.query}"</div>`;
|
||||
},
|
||||
};
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(inputConfig, 'templates')) {
|
||||
this.dataSetConfig.templates = {...defaultTemplates, ...inputConfig.templates};
|
||||
} else {
|
||||
this.dataSetConfig.templates = defaultTemplates;
|
||||
}
|
||||
|
||||
this.buildTypeahead();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the typeahead component based on provided configuration.
|
||||
*/
|
||||
buildTypeahead() {
|
||||
this.$searchInput.typeahead(this.config, this.dataSetConfig)
|
||||
.bind('typeahead:select', (e, selectedItem) => this.config.onSelect(selectedItem, e, this.$searchInput))
|
||||
.bind('typeahead:close', (e) => {
|
||||
this.config.onClose(e, this.$searchInput);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import Bloodhound from 'typeahead.js';
|
||||
|
||||
/**
|
||||
* This comes from Bloodhound it allows to create tokenizer based on multiple fields from an object.
|
||||
*
|
||||
* @param tokenizer
|
||||
* @returns {function(*=, ...[*]=): function(*): *[]}
|
||||
*/
|
||||
function getObjTokenizer(tokenizer) {
|
||||
return function setKey(keys, ...args) {
|
||||
const tokenizerKeys = _.isArray(keys) ? keys : [].slice.call(args, 0);
|
||||
|
||||
return function tokenize(val) {
|
||||
let tokens = [];
|
||||
tokenizerKeys.forEach((key) => {
|
||||
tokens = tokens.concat(tokenizer(_.toString(val[key])));
|
||||
});
|
||||
|
||||
return tokens;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the word into multiple tokens ok different sizes, thus allowing to search into parts of the words,
|
||||
* the min length of a token is two letters though (maybe it could be configurable in the future)
|
||||
*
|
||||
* @param {string} val
|
||||
*
|
||||
* @return {array}
|
||||
*/
|
||||
export const letters = (val) => {
|
||||
const tokens = Bloodhound.tokenizers.nonword(val);
|
||||
tokens.forEach((token) => {
|
||||
let i = 0;
|
||||
while (i + 1 < token.length) {
|
||||
tokens.push(token.substr(i, token.length));
|
||||
i += 1;
|
||||
}
|
||||
});
|
||||
|
||||
return tokens;
|
||||
};
|
||||
|
||||
export default {
|
||||
letters,
|
||||
obj: {
|
||||
letters: getObjTokenizer(letters),
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Generates a password and informs about it's strength.
|
||||
* You can pass a password input to watch the password strength and display feedback messages.
|
||||
* You can also generate a random password into an input.
|
||||
*/
|
||||
export default class ChangePasswordHandler {
|
||||
constructor(passwordStrengthFeedbackContainerSelector, options = {}) {
|
||||
// Minimum length of the generated password.
|
||||
this.minLength = options.minLength || 8;
|
||||
|
||||
// Feedback container holds messages representing password strength.
|
||||
this.$feedbackContainer = $(passwordStrengthFeedbackContainerSelector);
|
||||
|
||||
return {
|
||||
watchPasswordStrength: ($input) => this.watchPasswordStrength($input),
|
||||
generatePassword: ($input) => this.generatePassword($input),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch password, which is entered in the input, strength and inform about it.
|
||||
*
|
||||
* @param {jQuery} $input the input to watch.
|
||||
*/
|
||||
watchPasswordStrength($input) {
|
||||
$.passy.requirements.length.min = this.minLength;
|
||||
$.passy.requirements.characters = 'DIGIT';
|
||||
|
||||
$input.each((index, element) => {
|
||||
const $outputContainer = $('<span>');
|
||||
|
||||
$outputContainer.insertAfter($(element));
|
||||
|
||||
$(element).passy((strength, valid) => {
|
||||
this.displayFeedback($outputContainer, strength, valid);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a password and fills it to given input.
|
||||
*
|
||||
* @param {jQuery} $input the input to fill the password into.
|
||||
*/
|
||||
generatePassword($input) {
|
||||
$input.passy('generate', this.minLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display feedback about password's strength.
|
||||
*
|
||||
* @param {jQuery} $outputContainer a container to put feedback output into.
|
||||
* @param {number} passwordStrength
|
||||
* @param {boolean} isPasswordValid
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
displayFeedback($outputContainer, passwordStrength, isPasswordValid) {
|
||||
const feedback = this.getPasswordStrengthFeedback(passwordStrength);
|
||||
$outputContainer.text(feedback.message);
|
||||
$outputContainer.removeClass('text-danger text-warning text-success');
|
||||
$outputContainer.addClass(feedback.elementClass);
|
||||
$outputContainer.toggleClass('d-none', !isPasswordValid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get feedback that describes given password strength.
|
||||
* Response contains text message and element class.
|
||||
*
|
||||
* @param {number} strength
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
getPasswordStrengthFeedback(strength) {
|
||||
switch (strength) {
|
||||
case $.passy.strength.LOW:
|
||||
return {
|
||||
message: this.$feedbackContainer.find('.strength-low').text(),
|
||||
elementClass: 'text-danger',
|
||||
};
|
||||
|
||||
case $.passy.strength.MEDIUM:
|
||||
return {
|
||||
message: this.$feedbackContainer.find('.strength-medium').text(),
|
||||
elementClass: 'text-warning',
|
||||
};
|
||||
|
||||
case $.passy.strength.HIGH:
|
||||
return {
|
||||
message: this.$feedbackContainer.find('.strength-high').text(),
|
||||
elementClass: 'text-success',
|
||||
};
|
||||
|
||||
case $.passy.strength.EXTREME:
|
||||
return {
|
||||
message: this.$feedbackContainer.find('.strength-extreme').text(),
|
||||
elementClass: 'text-success',
|
||||
};
|
||||
|
||||
default:
|
||||
throw new Error('Invalid password strength indicator.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* ChoiceTable is responsible for managing common actions in choice table form type
|
||||
*/
|
||||
export default class ChoiceTable {
|
||||
/**
|
||||
* Init constructor
|
||||
*/
|
||||
constructor() {
|
||||
$(document).on('change', '.js-choice-table-select-all', (e) => {
|
||||
this.handleSelectAll(e);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check/uncheck all boxes in table
|
||||
*
|
||||
* @param {Event} event
|
||||
*/
|
||||
handleSelectAll(event) {
|
||||
const $selectAllCheckboxes = $(event.target);
|
||||
const isSelectAllChecked = $selectAllCheckboxes.is(':checked');
|
||||
|
||||
$selectAllCheckboxes.closest('table').find('tbody input:checkbox').prop('checked', isSelectAllChecked);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
export default {
|
||||
multistoreDropdown: {
|
||||
searchInput: '.js-multistore-dropdown-search',
|
||||
scrollbar: '.js-multistore-scrollbar',
|
||||
},
|
||||
multistoreHeader: {
|
||||
modal: '.js-multishop-modal',
|
||||
headerButton: '.js-header-multishop-open-modal',
|
||||
searchInput: '.js-multishop-modal-search',
|
||||
jsScrollbar: '.js-multishop-scrollbar',
|
||||
setContextUrl: (location, urlLetter, itemId) => {
|
||||
const setContextParameter = `setShopContext=${urlLetter}-${itemId}`;
|
||||
const url = new URL(location);
|
||||
|
||||
if (url.search === '') {
|
||||
url.search = `?${setContextParameter}`;
|
||||
} else {
|
||||
url.search += `&${setContextParameter}`;
|
||||
}
|
||||
|
||||
return url.toString();
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Toggle DNI input requirement on country selection
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* <!-- Country select options must have need_dni attribute when needed -->
|
||||
* <select name="id_country" id="id_country" states-url="path/to/states/api">
|
||||
* ...
|
||||
* <option value="6" need_dni="1">Spain</value>
|
||||
* ...
|
||||
* </select>
|
||||
*
|
||||
* In JS:
|
||||
*
|
||||
* new CountryDniRequiredToggler('#id_country', '#id_country_dni', 'label[for="id_country_dni"]');
|
||||
*/
|
||||
export default class CountryDniRequiredToggler {
|
||||
constructor(countryInputSelector, countryDniInput, countryDniInputLabel) {
|
||||
this.$countryDniInput = $(countryDniInput);
|
||||
this.$countryDniInputLabel = $(countryDniInputLabel);
|
||||
this.$countryInput = $(countryInputSelector);
|
||||
this.countryInputSelectedSelector = `${countryInputSelector}>option:selected`;
|
||||
this.countryDniInputLabelDangerSelector = `${countryDniInputLabel}>span.text-danger`;
|
||||
|
||||
// If field is required regardless of the country
|
||||
// keep it required
|
||||
if (this.$countryDniInput.attr('required')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$countryInput.on('change', () => this.toggle());
|
||||
|
||||
// toggle on page load
|
||||
this.toggle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles DNI input required
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggle() {
|
||||
$(this.countryDniInputLabelDangerSelector).remove();
|
||||
this.$countryDniInput.prop('required', false);
|
||||
if (parseInt($(this.countryInputSelectedSelector).attr('need_dni'), 10) === 1) {
|
||||
this.$countryDniInput.prop('required', true);
|
||||
this.$countryDniInputLabel.prepend($('<span class="text-danger">*</span>'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Toggle Postcode input requirement on country selection
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* <!-- Country select options must have need_postcode attribute when needed -->
|
||||
* <select name="id_country" id="id_country" states-url="path/to/states/api">
|
||||
* ...
|
||||
* <option value="6" need_postcode="1">Spain</value>
|
||||
* ...
|
||||
* </select>
|
||||
*
|
||||
* In JS:
|
||||
*
|
||||
* new CountryPostcodeRequiredToggler('#id_country', '#id_country_postcode', 'label[for="id_country_postcode"]');
|
||||
*/
|
||||
export default class CountryPostcodeRequiredToggler {
|
||||
constructor(countryInputSelector, countryPostcodeInput, countryPostcodeInputLabel) {
|
||||
this.$countryPostcodeInput = $(countryPostcodeInput);
|
||||
this.$countryPostcodeInputLabel = $(countryPostcodeInputLabel);
|
||||
this.$countryInput = $(countryInputSelector);
|
||||
this.countryInputSelectedSelector = `${countryInputSelector}>option:selected`;
|
||||
this.countryPostcodeInputLabelDangerSelector = `${countryPostcodeInputLabel}>span.text-danger`;
|
||||
|
||||
// If field is required regardless of the country
|
||||
// keep it required
|
||||
if (this.$countryPostcodeInput.attr('required')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$countryInput.on('change', () => this.toggle());
|
||||
|
||||
// toggle on page load
|
||||
this.toggle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles Postcode input required
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggle() {
|
||||
$(this.countryPostcodeInputLabelDangerSelector).remove();
|
||||
this.$countryPostcodeInput.prop('required', false);
|
||||
if (parseInt($(this.countryInputSelectedSelector).attr('need_postcode'), 10) === 1) {
|
||||
this.$countryPostcodeInput.prop('required', true);
|
||||
this.$countryPostcodeInputLabel.prepend($('<span class="text-danger">*</span>'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Displays, fills or hides State selection block depending on selected country.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* <!-- Country select must have unique identifier & url for states API -->
|
||||
* <select name="id_country" id="id_country" states-url="path/to/states/api">
|
||||
* ...
|
||||
* </select>
|
||||
*
|
||||
* <!-- If selected country does not have states, then this block will be hidden -->
|
||||
* <div class="js-state-selection-block">
|
||||
* <select name="id_state">
|
||||
* ...
|
||||
* </select>
|
||||
* </div>
|
||||
*
|
||||
* In JS:
|
||||
*
|
||||
* new CountryStateSelectionToggler('#id_country', '#id_state', '.js-state-selection-block');
|
||||
*/
|
||||
export default class CountryStateSelectionToggler {
|
||||
constructor(countryInputSelector, countryStateSelector, stateSelectionBlockSelector) {
|
||||
this.$stateSelectionBlock = $(stateSelectionBlockSelector);
|
||||
this.$countryStateSelector = $(countryStateSelector);
|
||||
this.$countryInput = $(countryInputSelector);
|
||||
|
||||
this.$countryInput.on('change', () => this.change());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Change State selection
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
change() {
|
||||
const countryId = this.$countryInput.val();
|
||||
|
||||
if (countryId === '') {
|
||||
return;
|
||||
}
|
||||
$.get({
|
||||
url: this.$countryInput.data('states-url'),
|
||||
dataType: 'json',
|
||||
data: {
|
||||
id_country: countryId,
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
this.$countryStateSelector.empty();
|
||||
|
||||
Object.keys(response.states).forEach((value) => {
|
||||
this.$countryStateSelector.append(
|
||||
$('<option></option>')
|
||||
.attr('value', response.states[value])
|
||||
.text(value),
|
||||
);
|
||||
});
|
||||
|
||||
this.toggle();
|
||||
})
|
||||
.catch((response) => {
|
||||
if (typeof response.responseJSON !== 'undefined') {
|
||||
window.showErrorMessage(response.responseJSON.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this.$stateSelectionBlock.toggleClass('d-none', !this.$countryStateSelector.find('option').length > 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import AutoCompleteSearch from '@components/auto-complete-search';
|
||||
import Bloodhound from 'typeahead.js';
|
||||
|
||||
/**
|
||||
* This component is used to search and select an entity, it is uses the AutoSearchComplete
|
||||
* component which displays a list of suggestion based on an API returned response. Then when
|
||||
* an element is selected it is added to the selection container and hidden inputs are created to
|
||||
* send an array of entity IDs in the form request.
|
||||
*
|
||||
* This component is used with TypeaheadType forms, and is tightly linked to the content of this
|
||||
* twig file src/PrestaShopBundle/Resources/views/Admin/TwigTemplateForm/typeahead.html.twig
|
||||
*
|
||||
* @todo: the component relies on this TypeaheadType because it was the historical type but it would be worth
|
||||
* creating a new clean form type with better templating (the tplcollection brings nearly no value as is)
|
||||
*/
|
||||
export default class EntitySearchInput {
|
||||
constructor($entitySearchInput, options) {
|
||||
this.$entitySearchInput = $entitySearchInput;
|
||||
this.entitySearchInputId = this.$entitySearchInput.prop('id');
|
||||
this.$autoCompleteSearchContainer = this.$entitySearchInput.closest('.autocomplete-search');
|
||||
this.$selectionContainer = $(`#${this.entitySearchInputId}-data`);
|
||||
this.searchInputFullName = this.$autoCompleteSearchContainer.data('fullname');
|
||||
|
||||
const inputOptions = options || {};
|
||||
this.options = {
|
||||
value: 'id',
|
||||
dataLimit: 1,
|
||||
...inputOptions,
|
||||
};
|
||||
this.buildRemoteSource();
|
||||
this.buildAutoCompleteSearch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the remote url of the endpoint that returns suggestions.
|
||||
*
|
||||
* @param remoteUrl {string}
|
||||
*/
|
||||
setRemoteUrl(remoteUrl) {
|
||||
this.entityRemoteSource.remote.url = remoteUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force selected values, the input is an array of object that must match the format from
|
||||
* the API if you want the selected entities to be correctly displayed.
|
||||
*
|
||||
* @param values {array}
|
||||
*/
|
||||
setValue(values) {
|
||||
this.clearSelectedItems();
|
||||
if (!values || values.length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
values.each((value) => {
|
||||
this.appendSelectedItem(value);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the AutoCompleteSearch component
|
||||
*/
|
||||
buildAutoCompleteSearch() {
|
||||
const autoSearchConfig = {
|
||||
source: this.entityRemoteSource,
|
||||
dataLimit: this.options.dataLimit,
|
||||
templates: {
|
||||
suggestion: (entity) => {
|
||||
let entityImage;
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(entity, 'image')) {
|
||||
entityImage = `<img src="${entity.image}" /> `;
|
||||
}
|
||||
|
||||
return `<div class="search-suggestion">${entityImage}${entity.name}</div>`;
|
||||
},
|
||||
},
|
||||
onClose: (event) => {
|
||||
this.onSelectionClose(event);
|
||||
},
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
onSelect: (selectedItem, event) => {
|
||||
// When limit is one we cannot select additional elements so we replace them instead
|
||||
if (this.options.dataLimit === 1) {
|
||||
return this.replaceSelectedItem(selectedItem);
|
||||
}
|
||||
return this.appendSelectedItem(selectedItem);
|
||||
},
|
||||
};
|
||||
|
||||
// Can be used to format value depending on selected item
|
||||
if (this.options.value !== undefined) {
|
||||
autoSearchConfig.value = this.options.value;
|
||||
}
|
||||
this.autoSearch = new AutoCompleteSearch(this.$entitySearchInput, autoSearchConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Bloodhound remote source which will call the API. The placeholder to
|
||||
* inject the query search parameter is __QUERY__ (@todo: could be configurable)
|
||||
*
|
||||
* @returns {Bloodhound}
|
||||
*/
|
||||
buildRemoteSource() {
|
||||
const sourceConfig = {
|
||||
mappingValue: this.$autoCompleteSearchContainer.data('mappingvalue'),
|
||||
remoteUrl: this.$autoCompleteSearchContainer.data('remoteurl'),
|
||||
};
|
||||
|
||||
this.entityRemoteSource = new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
identify(obj) {
|
||||
return obj[sourceConfig.mappingValue];
|
||||
},
|
||||
remote: {
|
||||
url: sourceConfig.remoteUrl,
|
||||
cache: false,
|
||||
wildcard: '__QUERY__',
|
||||
transform(response) {
|
||||
if (!response) {
|
||||
return [];
|
||||
}
|
||||
return response;
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* When an item is selected we empty the input search, since the selected data is stored in hidden inputs anyway
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
onSelectionClose(event) {
|
||||
$(event.target).val('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes selected items.
|
||||
*/
|
||||
clearSelectedItems() {
|
||||
const formIdItem = $('li', this.$selectionContainer);
|
||||
formIdItem.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* When the component is configured to have only one selected element on each selection
|
||||
* the previous selection is removed and then replaced.
|
||||
*
|
||||
* @param selectedItem {Object}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
replaceSelectedItem(selectedItem) {
|
||||
this.clearSelectedItems();
|
||||
this.addSelectedContentToContainer(selectedItem);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the component is configured to have more than one selected item on each selection
|
||||
* the item is added to the list.
|
||||
*
|
||||
* @param selectedItem {Object}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
appendSelectedItem(selectedItem) {
|
||||
// If collection length is up to limit, return
|
||||
const formIdItem = $('li', this.$selectionContainer);
|
||||
|
||||
if (this.options.dataLimit !== 0 && formIdItem.length >= this.options.dataLimit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.addSelectedContentToContainer(selectedItem);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the selected content to the selection container, the HTML is generated based on the render function
|
||||
* then a hidden input is automatically added inside it, and finally the rendered selection is added to the list.
|
||||
*
|
||||
* @param selectedItem {Object}
|
||||
*/
|
||||
addSelectedContentToContainer(selectedItem) {
|
||||
let value;
|
||||
|
||||
if (typeof this.options.value === 'function') {
|
||||
value = this.options.value(selectedItem);
|
||||
} else {
|
||||
value = selectedItem[this.options.value];
|
||||
}
|
||||
|
||||
const selectedHtml = this.renderSelected(selectedItem);
|
||||
// Hidden input is added into the selected li
|
||||
const $selectedNode = $(selectedHtml);
|
||||
const $hiddenInput = $(`<input type="hidden" name="${this.searchInputFullName}[data][]" value="${value}" />`);
|
||||
$selectedNode.append($hiddenInput);
|
||||
|
||||
// Then the li is added to the list
|
||||
this.$selectionContainer.append($selectedNode);
|
||||
|
||||
// Trigger the change so that listeners detect the form data has been modified
|
||||
$hiddenInput.trigger('change');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the selected element, this will be appended in the selection list (ul),
|
||||
* no need to include the hidden input as it is automatically handled in addSelectedContentToContainer
|
||||
*
|
||||
* @param entity {Object}
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
renderSelected(entity) {
|
||||
// @todo: the tplcollection idea is not bad but it only contains a span for now, to fo to the end of this idea
|
||||
// it should contain the whole div (with media-left media-body and all)
|
||||
const $templateContainer = $(`#tplcollection-${this.entitySearchInputId}`);
|
||||
const innerTemplateHtml = $templateContainer
|
||||
.html()
|
||||
.replace('%s', entity.name);
|
||||
|
||||
return `<li class="media">
|
||||
<div class="media-left">
|
||||
<img class="media-object image" src="${entity.image}" />
|
||||
</div>
|
||||
<div class="media-body media-middle">
|
||||
${innerTemplateHtml}
|
||||
</div>
|
||||
</li>`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import EventEmitterClass from 'events';
|
||||
|
||||
/**
|
||||
* We instanciate one EventEmitter (restricted via a const) so that every components
|
||||
* register/dispatch on the same one and can communicate with each other.
|
||||
*/
|
||||
export const EventEmitter = new EventEmitterClass();
|
||||
|
||||
export default EventEmitter;
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Component which allows submitting very simple forms without having to use <form> element.
|
||||
*
|
||||
* Useful when performing actions on resource where URL contains all needed data.
|
||||
* For example, to toggle category status via "POST /categories/2/toggle-status)"
|
||||
* or delete cover image via "POST /categories/2/delete-cover-image".
|
||||
*
|
||||
* Usage example in template:
|
||||
*
|
||||
* <button class="js-form-submit-btn"
|
||||
* data-form-submit-url="/my-custom-url" // (required) URL to which form will be submitted
|
||||
* data-method="GET|POST|DELETE|PATCH" // (optional) specify the verb to use for the request.
|
||||
* // POST is taken by default if not value is set
|
||||
* data-form-csrf-token="my-generated-csrf-token" // (optional) to increase security
|
||||
* data-form-confirm-message="Are you sure?" // (optional) to confirm action before submit
|
||||
* type="button" // make sure its simple button
|
||||
* // so we can avoid submitting actual form
|
||||
* // when our button is defined inside form
|
||||
* >
|
||||
* Click me to submit form
|
||||
* </button>
|
||||
*
|
||||
* In page specific JS you have to enable this feature:
|
||||
*
|
||||
* new FormSubmitButton();
|
||||
*/
|
||||
export default class FormSubmitButton {
|
||||
constructor() {
|
||||
$(document).on('click', '.js-form-submit-btn', function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
const $btn = $(this);
|
||||
|
||||
if ($btn.data('form-confirm-message') && window.confirm($btn.data('form-confirm-message')) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
let method = 'POST';
|
||||
let addInput = null;
|
||||
|
||||
if ($btn.data('method')) {
|
||||
const btnMethod = $btn.data('method');
|
||||
const isGetOrPostMethod = ['GET', 'POST'].includes(btnMethod);
|
||||
method = isGetOrPostMethod ? btnMethod : 'POST';
|
||||
|
||||
if (!isGetOrPostMethod) {
|
||||
addInput = $('<input>', {
|
||||
type: '_hidden',
|
||||
name: '_method',
|
||||
value: btnMethod,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const $form = $('<form>', {
|
||||
action: $btn.data('form-submit-url'),
|
||||
method,
|
||||
});
|
||||
|
||||
if (addInput) {
|
||||
$form.append(addInput);
|
||||
}
|
||||
|
||||
if ($btn.data('form-csrf-token')) {
|
||||
$form.append($('<input>', {
|
||||
type: '_hidden',
|
||||
name: '_csrf_token',
|
||||
value: $btn.data('form-csrf-token'),
|
||||
}));
|
||||
}
|
||||
|
||||
$form.appendTo('body').submit();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
export default class AutocompleteWithEmail {
|
||||
constructor(emailInputSelector, map = []) {
|
||||
this.map = map;
|
||||
this.$emailInput = $(emailInputSelector);
|
||||
this.$emailInput.on('change', () => this.change());
|
||||
}
|
||||
|
||||
change() {
|
||||
$.get({
|
||||
url: this.$emailInput.data('customer-information-url'),
|
||||
dataType: 'json',
|
||||
data: {
|
||||
email: this.$emailInput.val(),
|
||||
},
|
||||
}).then((response) => {
|
||||
Object.keys(this.map).forEach((key) => {
|
||||
if (response[key] !== undefined) {
|
||||
$(this.map[key]).val(response[key]);
|
||||
}
|
||||
});
|
||||
}).catch((response) => {
|
||||
if (typeof response.responseJSON !== 'undefined') {
|
||||
window.showErrorMessage(response.responseJSON.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import ChangePasswordHandler from '../change-password-handler';
|
||||
import PasswordValidator from '../password-validator';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class responsible for actions related to "change password" form type.
|
||||
* Generates random passwords, validates new password and it's confirmation,
|
||||
* displays error messages related to validation.
|
||||
*/
|
||||
export default class ChangePasswordControl {
|
||||
constructor(
|
||||
inputsBlockSelector,
|
||||
showButtonSelector,
|
||||
hideButtonSelector,
|
||||
generatePasswordButtonSelector,
|
||||
oldPasswordInputSelector,
|
||||
newPasswordInputSelector,
|
||||
confirmNewPasswordInputSelector,
|
||||
generatedPasswordDisplaySelector,
|
||||
passwordStrengthFeedbackContainerSelector,
|
||||
) {
|
||||
// Block that contains password inputs
|
||||
this.$inputsBlock = $(inputsBlockSelector);
|
||||
|
||||
// Button that shows the password inputs block
|
||||
this.showButtonSelector = showButtonSelector;
|
||||
|
||||
// Button that hides the password inputs block
|
||||
this.hideButtonSelector = hideButtonSelector;
|
||||
|
||||
// Button that generates a random password
|
||||
this.generatePasswordButtonSelector = generatePasswordButtonSelector;
|
||||
|
||||
// Input to enter old password
|
||||
this.oldPasswordInputSelector = oldPasswordInputSelector;
|
||||
|
||||
// Input to enter new password
|
||||
this.newPasswordInputSelector = newPasswordInputSelector;
|
||||
|
||||
// Input to confirm the new password
|
||||
this.confirmNewPasswordInputSelector = confirmNewPasswordInputSelector;
|
||||
|
||||
// Input that displays generated random password
|
||||
this.generatedPasswordDisplaySelector = generatedPasswordDisplaySelector;
|
||||
|
||||
// Main input for password generation
|
||||
this.$newPasswordInputs = this.$inputsBlock
|
||||
.find(this.newPasswordInputSelector);
|
||||
|
||||
// Generated password will be copied to these inputs
|
||||
this.$copyPasswordInputs = this.$inputsBlock
|
||||
.find(this.confirmNewPasswordInputSelector)
|
||||
.add(this.generatedPasswordDisplaySelector);
|
||||
|
||||
// All inputs in the change password block, that are submittable with the form.
|
||||
this.$submittableInputs = this.$inputsBlock
|
||||
.find(this.oldPasswordInputSelector)
|
||||
.add(this.newPasswordInputSelector)
|
||||
.add(this.confirmNewPasswordInputSelector);
|
||||
|
||||
this.passwordHandler = new ChangePasswordHandler(
|
||||
passwordStrengthFeedbackContainerSelector,
|
||||
);
|
||||
|
||||
this.passwordValidator = new PasswordValidator(
|
||||
this.newPasswordInputSelector,
|
||||
this.confirmNewPasswordInputSelector,
|
||||
);
|
||||
|
||||
this.hideInputsBlock();
|
||||
this.initEvents();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize events.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
initEvents() {
|
||||
// Show the inputs block when show button is clicked
|
||||
$(document).on('click', this.showButtonSelector, (e) => {
|
||||
this.hide($(e.currentTarget));
|
||||
this.showInputsBlock();
|
||||
});
|
||||
|
||||
$(document).on('click', this.hideButtonSelector, () => {
|
||||
this.hideInputsBlock();
|
||||
this.show($(this.showButtonSelector));
|
||||
});
|
||||
|
||||
// Watch and display feedback about password's strength
|
||||
this.passwordHandler.watchPasswordStrength(this.$newPasswordInputs);
|
||||
|
||||
$(document).on('click', this.generatePasswordButtonSelector, () => {
|
||||
// Generate the password into main input.
|
||||
this.passwordHandler.generatePassword(this.$newPasswordInputs);
|
||||
|
||||
// Copy the generated password from main input to additional inputs
|
||||
this.$copyPasswordInputs.val(this.$newPasswordInputs.val());
|
||||
this.checkPasswordValidity();
|
||||
});
|
||||
|
||||
// Validate new password and it's confirmation when any of the inputs is changed
|
||||
$(document).on(
|
||||
'keyup',
|
||||
`${this.newPasswordInputSelector},${this.confirmNewPasswordInputSelector}`,
|
||||
() => {
|
||||
this.checkPasswordValidity();
|
||||
},
|
||||
);
|
||||
|
||||
// Prevent submitting the form if new password is not valid
|
||||
$(document).on('submit', $(this.oldPasswordInputSelector).closest('form'), (event) => {
|
||||
// If password input is disabled - we don't need to validate it.
|
||||
if ($(this.oldPasswordInputSelector).is(':disabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.passwordValidator.isPasswordValid()) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if password is valid, show error messages if it's not.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
checkPasswordValidity() {
|
||||
const $firstPasswordErrorContainer = $(this.newPasswordInputSelector).parent().find('.form-text');
|
||||
const $secondPasswordErrorContainer = $(this.confirmNewPasswordInputSelector).parent().find('.form-text');
|
||||
|
||||
$firstPasswordErrorContainer
|
||||
.text(this.getPasswordLengthValidationMessage())
|
||||
.toggleClass('text-danger', !this.passwordValidator.isPasswordLengthValid());
|
||||
$secondPasswordErrorContainer
|
||||
.text(this.getPasswordConfirmationValidationMessage())
|
||||
.toggleClass('text-danger', !this.passwordValidator.isPasswordMatchingConfirmation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get password confirmation validation message.
|
||||
*
|
||||
* @returns {String}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
getPasswordConfirmationValidationMessage() {
|
||||
if (!this.passwordValidator.isPasswordMatchingConfirmation()) {
|
||||
return $(this.confirmNewPasswordInputSelector).data('invalid-password');
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get password length validation message.
|
||||
*
|
||||
* @returns {String}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
getPasswordLengthValidationMessage() {
|
||||
if (this.passwordValidator.isPasswordTooShort()) {
|
||||
return $(this.newPasswordInputSelector).data('password-too-short');
|
||||
}
|
||||
|
||||
if (this.passwordValidator.isPasswordTooLong()) {
|
||||
return $(this.newPasswordInputSelector).data('password-too-long');
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the password inputs block.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
showInputsBlock() {
|
||||
this.show(this.$inputsBlock);
|
||||
this.$submittableInputs.removeAttr('disabled');
|
||||
this.$submittableInputs.attr('required', 'required');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the password inputs block.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
hideInputsBlock() {
|
||||
this.hide(this.$inputsBlock);
|
||||
this.$submittableInputs.attr('disabled', 'disabled');
|
||||
this.$submittableInputs.removeAttr('required');
|
||||
this.$inputsBlock.find('input').val('');
|
||||
this.$inputsBlock.find('.form-text').text('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide an element.
|
||||
*
|
||||
* @param {jQuery} $el
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
hide($el) {
|
||||
$el.addClass('d-none');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show hidden element.
|
||||
*
|
||||
* @param {jQuery} $el
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
show($el) {
|
||||
$el.removeClass('d-none');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Handles UI interactions of choice tree
|
||||
*/
|
||||
export default class ChoiceTree {
|
||||
/**
|
||||
* @param {String} treeSelector
|
||||
*/
|
||||
constructor(treeSelector) {
|
||||
this.$container = $(treeSelector);
|
||||
|
||||
this.$container.on('click', '.js-input-wrapper', (event) => {
|
||||
const $inputWrapper = $(event.currentTarget);
|
||||
|
||||
this.toggleChildTree($inputWrapper);
|
||||
});
|
||||
|
||||
this.$container.on('click', '.js-toggle-choice-tree-action', (event) => {
|
||||
const $action = $(event.currentTarget);
|
||||
|
||||
this.toggleTree($action);
|
||||
});
|
||||
|
||||
return {
|
||||
enableAutoCheckChildren: () => this.enableAutoCheckChildren(),
|
||||
enableAllInputs: () => this.enableAllInputs(),
|
||||
disableAllInputs: () => this.disableAllInputs(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable automatic check/uncheck of clicked item's children.
|
||||
*/
|
||||
enableAutoCheckChildren() {
|
||||
this.$container.on('change', 'input[type="checkbox"]', (event) => {
|
||||
const $clickedCheckbox = $(event.currentTarget);
|
||||
const $itemWithChildren = $clickedCheckbox.closest('li');
|
||||
|
||||
$itemWithChildren
|
||||
.find('ul input[type="checkbox"]')
|
||||
.prop('checked', $clickedCheckbox.is(':checked'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable all inputs in the choice tree.
|
||||
*/
|
||||
enableAllInputs() {
|
||||
this.$container.find('input').removeAttr('disabled');
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable all inputs in the choice tree.
|
||||
*/
|
||||
disableAllInputs() {
|
||||
this.$container.find('input').attr('disabled', 'disabled');
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse or expand sub-tree for single parent
|
||||
*
|
||||
* @param {jQuery} $inputWrapper
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggleChildTree($inputWrapper) {
|
||||
const $parentWrapper = $inputWrapper.closest('li');
|
||||
|
||||
if ($parentWrapper.hasClass('expanded')) {
|
||||
$parentWrapper
|
||||
.removeClass('expanded')
|
||||
.addClass('collapsed');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($parentWrapper.hasClass('collapsed')) {
|
||||
$parentWrapper
|
||||
.removeClass('collapsed')
|
||||
.addClass('expanded');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse or expand whole tree
|
||||
*
|
||||
* @param {jQuery} $action
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggleTree($action) {
|
||||
const $parentContainer = $action.closest('.js-choice-tree-container');
|
||||
const action = $action.data('action');
|
||||
|
||||
// toggle action configuration
|
||||
const config = {
|
||||
addClass: {
|
||||
expand: 'expanded',
|
||||
collapse: 'collapsed',
|
||||
},
|
||||
removeClass: {
|
||||
expand: 'collapsed',
|
||||
collapse: 'expanded',
|
||||
},
|
||||
nextAction: {
|
||||
expand: 'collapse',
|
||||
collapse: 'expand',
|
||||
},
|
||||
text: {
|
||||
expand: 'collapsed-text',
|
||||
collapse: 'expanded-text',
|
||||
},
|
||||
icon: {
|
||||
expand: 'collapsed-icon',
|
||||
collapse: 'expanded-icon',
|
||||
},
|
||||
};
|
||||
|
||||
$parentContainer.find('li').each((index, item) => {
|
||||
const $item = $(item);
|
||||
|
||||
if ($item.hasClass(config.removeClass[action])) {
|
||||
$item.removeClass(config.removeClass[action])
|
||||
.addClass(config.addClass[action]);
|
||||
}
|
||||
});
|
||||
|
||||
$action.data('action', config.nextAction[action]);
|
||||
$action.find('.material-icons').text($action.data(config.icon[action]));
|
||||
$action.find('.js-toggle-text').text($action.data(config.text[action]));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,390 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* This is able to watch an HTML form and parse it as a Javascript object based on a configurable
|
||||
* mapping. Each field from the model is mapped to a form input, or several, each input is watched
|
||||
* to keep the model consistent.
|
||||
*
|
||||
* The model mapping used for this component is an object which uses the modelKey as a key (it represents
|
||||
* the property path in the object, separated by a dot) and the input names as value (they follow Symfony
|
||||
* convention naming using brackets). Here is an example of mapping:
|
||||
*
|
||||
* const modelMapping = {
|
||||
* 'product.stock.quantity': 'product[stock][quantity]',
|
||||
* 'product.price.priceTaxExcluded': [
|
||||
* 'product[price][price_tax_excluded]',
|
||||
* 'product[shortcuts][price][price_tax_excluded]',
|
||||
* ],
|
||||
* };
|
||||
*
|
||||
* As you can see for priceTaxExcluded it is possible to assign multiple inputs to the same modelKey, thus
|
||||
* any update in one of the inputs will update the model, and all these inputs are kept in sync.
|
||||
*
|
||||
* With the previous configuration this component would return an object that looks like this:
|
||||
*
|
||||
* {
|
||||
* product: {
|
||||
* stock: {
|
||||
* // Mapped to product[stock][quantity] input
|
||||
* quantity: 200,
|
||||
* },
|
||||
* price: {
|
||||
* // Mapped to two inputs product[price][price_tax_excluded] and product[shortcuts][price][price_tax_excluded]
|
||||
* priceTaxExcluded: 20.45,
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
export default class FormObjectMapper {
|
||||
/**
|
||||
* @param {jQuery} $form - Form element to attach the mapper to
|
||||
* @param {Object} modelMapping - Structure mapping a model to form names
|
||||
* @param {EventEmitter} eventEmitter
|
||||
* @param {Object} [config] - Event names
|
||||
* @param {Object} [config.updateModel] - Name of the event to listen to trigger a refresh of the model update
|
||||
* @param {Object} [config.modelUpdated] - Name of the event emitted each time the model is updated
|
||||
* @param {Object} [config.modelFieldUpdated] - Name of the event emitted each time a field is updated
|
||||
* @return {Object}
|
||||
*/
|
||||
constructor($form, modelMapping, eventEmitter, config) {
|
||||
this.$form = $form;
|
||||
this.fullModelMapping = modelMapping;
|
||||
this.eventEmitter = eventEmitter;
|
||||
|
||||
const inputConfig = config || {};
|
||||
|
||||
// This event is registered so when it is triggered it forces the form mapping and object update,
|
||||
// it can be useful when some new inputs have been added in the DOM (or removed) so that the model
|
||||
// acknowledges the update
|
||||
this.updateModelEventName = inputConfig.updateModel || 'updateModel';
|
||||
|
||||
// This event is emitted each time the object is updated (from both input change and external event)
|
||||
this.modelUpdatedEventName = inputConfig.modelUpdated || 'modelUpdated';
|
||||
// This event is emitted each time an object field is updated (from both input change and external event)
|
||||
this.modelFieldUpdatedEventName = inputConfig.modelFieldUpdated || 'modelFieldUpdated';
|
||||
|
||||
// Contains callbacks identified by model keys
|
||||
this.watchedProperties = {};
|
||||
|
||||
this.initFormMapping();
|
||||
this.updateFullObject();
|
||||
this.watchUpdates();
|
||||
|
||||
return {
|
||||
/**
|
||||
* Returns the model mapped to the form (current live state)
|
||||
*
|
||||
* @returns {*|{}}
|
||||
*/
|
||||
getModel: () => this.model,
|
||||
|
||||
/**
|
||||
* Returns all inputs associated to a model field.
|
||||
*
|
||||
* @param {string} modelKey
|
||||
*
|
||||
* @returns {undefined|jQuery}
|
||||
*/
|
||||
getInputsFor: (modelKey) => {
|
||||
if (!Object.prototype.hasOwnProperty.call(this.fullModelMapping, modelKey)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const inputNames = this.fullModelMapping[modelKey];
|
||||
|
||||
// We must loop manually to keep the order in configuration, if we use jQuery multiple selectors the collection
|
||||
// will be filled respecting the order in the DOM
|
||||
const inputs = [];
|
||||
const domForm = this.$form.get(0);
|
||||
inputNames.forEach((inputName) => {
|
||||
const inputsByName = domForm.querySelectorAll(`[name="${inputName}"]`);
|
||||
|
||||
if (inputsByName.length) {
|
||||
inputsByName.forEach((input) => {
|
||||
inputs.push(input);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return inputs.length ? $(inputs) : undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a value to a field of the object based on the model key, the object itself is updated
|
||||
* of course but the mapped inputs are also synced (all of them if multiple). Events are also
|
||||
* triggered to indicate the object has been updated (the general and the individual field ones).
|
||||
*
|
||||
* @param {string} modelKey
|
||||
* @param {*|{}} value
|
||||
*/
|
||||
set: (modelKey, value) => {
|
||||
if (!Object.prototype.hasOwnProperty.call(this.modelMapping, modelKey) || value === this.getValue(modelKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// First update the inputs then the model, so that the event is sent at last
|
||||
this.updateInputValue(modelKey, value);
|
||||
this.updateObjectByKey(modelKey, value);
|
||||
this.eventEmitter.emit(this.modelUpdatedEventName, this.model);
|
||||
},
|
||||
|
||||
/**
|
||||
* Alternative to the event listening, you can watch a specific field of the model and assign a callback.
|
||||
* When the specified model field is updated the event is still thrown but additionally any callback assigned
|
||||
* to this specific value is also called, the parameter is the same event.
|
||||
*
|
||||
* @param {string} modelKey
|
||||
* @param {function} callback
|
||||
*/
|
||||
watch: (modelKey, callback) => {
|
||||
if (!Object.prototype.hasOwnProperty.call(this.watchedProperties, modelKey)) {
|
||||
this.watchedProperties[modelKey] = [];
|
||||
}
|
||||
this.watchedProperties[modelKey].push(callback);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field from the object based on the model key, you can even get a sub part of the whole model,
|
||||
* this internal method is used by both get and set public methods.
|
||||
*
|
||||
* @param {string} modelKey
|
||||
*
|
||||
* @returns {*|{}|undefined} Returns any element from the model, undefined if not found
|
||||
* @private
|
||||
*/
|
||||
getValue(modelKey) {
|
||||
const modelKeys = modelKey.split('.');
|
||||
|
||||
return $.serializeJSON.deepGet(this.model, modelKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Watches if changes happens from the form or via an event.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
watchUpdates() {
|
||||
this.$form.on('keyup change dp.change', ':input', _.debounce(
|
||||
(event) => this.inputUpdated(event),
|
||||
350,
|
||||
{maxWait: 1500},
|
||||
));
|
||||
this.eventEmitter.on(this.updateModelEventName, () => this.updateFullObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when a form input has been changed.
|
||||
*
|
||||
* @param {jQuery.Event} event
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
inputUpdated(event) {
|
||||
const target = event.currentTarget;
|
||||
|
||||
// All inputs changes are watched, but not all of them are part of the mapping so we ignore them
|
||||
if (!Object.prototype.hasOwnProperty.call(this.formMapping, target.name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedValue = $(target).val();
|
||||
const updatedModelKey = this.formMapping[target.name];
|
||||
|
||||
// Update the mapped input fields
|
||||
this.updateInputValue(updatedModelKey, updatedValue, target.name);
|
||||
|
||||
// Then update model and emit event
|
||||
this.updateObjectByKey(updatedModelKey, updatedValue);
|
||||
this.eventEmitter.emit(this.modelUpdatedEventName, this.model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all the inputs mapped to a model key
|
||||
*
|
||||
* @param {string} modelKey
|
||||
* @param {*|{}} value
|
||||
* @param {string|undefined} sourceInputName Source of the change (no need to update it)
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
updateInputValue(modelKey, value, sourceInputName = undefined) {
|
||||
const modelInputs = this.fullModelMapping[modelKey];
|
||||
|
||||
// Update linked inputs (when there is more than one input associated to the model field)
|
||||
if (Array.isArray(modelInputs)) {
|
||||
modelInputs.forEach((inputName) => {
|
||||
if (sourceInputName === inputName) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateInputByName(inputName, value);
|
||||
});
|
||||
} else if (sourceInputName !== modelInputs) {
|
||||
this.updateInputByName(modelInputs, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update individual input based on its name
|
||||
*
|
||||
* @param {string} inputName
|
||||
* @param {*|{}} value
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
updateInputByName(inputName, value) {
|
||||
const $input = $(`[name="${inputName}"]`, this.$form);
|
||||
|
||||
if (!$input.length) {
|
||||
console.error(`Input with name ${inputName} is not present in form.`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// This check is important to avoid infinite loops, we don't use strict equality on purpose because it would result
|
||||
// into a potential infinite loop if type don't match, which can easily happen with a number value and a text input.
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if ($input.val() != value) {
|
||||
$input.val(value);
|
||||
|
||||
if ($input.data('toggle') === 'select2') {
|
||||
// This is required for select2, because only changing the val doesn't update the wrapping component
|
||||
$input.trigger('change');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes and updates the object based on form content and the mapping configuration, finally
|
||||
* emit an event for external components that may need the update.
|
||||
*
|
||||
* This method is called when this component initializes or when triggered by an external event.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
updateFullObject() {
|
||||
const serializedForm = this.$form.serializeJSON();
|
||||
this.model = {};
|
||||
Object.keys(this.modelMapping).forEach((modelKey) => {
|
||||
const formMapping = this.modelMapping[modelKey];
|
||||
const formKeys = $.serializeJSON.splitInputNameIntoKeysArray(formMapping);
|
||||
const formValue = $.serializeJSON.deepGet(serializedForm, formKeys);
|
||||
|
||||
this.updateObjectByKey(modelKey, formValue);
|
||||
});
|
||||
|
||||
this.eventEmitter.emit(this.modelUpdatedEventName, this.model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a specific field of the object.
|
||||
*
|
||||
* @param {string} modelKey
|
||||
* @param {*|{}} value
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
updateObjectByKey(modelKey, value) {
|
||||
const modelKeys = modelKey.split('.');
|
||||
const previousValue = $.serializeJSON.deepGet(this.model, modelKeys);
|
||||
|
||||
// This check has two interests, there is no point in modifying a value or emit an event for a value that did not
|
||||
// change, and it avoids infinite loops when the object field are co-dependent and need to be updated dynamically
|
||||
// (ex: update price tax included when price tax excluded is updated and vice versa, without this check an infinite
|
||||
// loop would happen)
|
||||
if (previousValue === value) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.serializeJSON.deepSet(this.model, modelKeys, value);
|
||||
|
||||
const updateEvent = {
|
||||
object: this.model,
|
||||
modelKey,
|
||||
value,
|
||||
previousValue,
|
||||
};
|
||||
this.eventEmitter.emit(this.modelFieldUpdatedEventName, updateEvent);
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.watchedProperties, modelKey)) {
|
||||
const propertyWatchers = this.watchedProperties[modelKey];
|
||||
propertyWatchers.forEach((callback) => {
|
||||
callback(updateEvent);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the initial mapping Model->Form to the opposite Form->Model
|
||||
* This simplifies the sync in when data updates.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
initFormMapping() {
|
||||
// modelMapping is a light version of the fullModelMapping, it only contains one input name which is considered
|
||||
// as the default one (when full object is updated, only the default input is used)
|
||||
this.modelMapping = {};
|
||||
|
||||
// formMapping is the inverse of modelMapping for each input name it associated the model key, it is generated for
|
||||
// performance and convenience, this allows to get mapping data faster in other functions
|
||||
this.formMapping = {};
|
||||
|
||||
Object.keys(this.fullModelMapping).forEach((modelKey) => {
|
||||
const formMapping = this.fullModelMapping[modelKey];
|
||||
|
||||
if (Array.isArray(formMapping)) {
|
||||
formMapping.forEach((aliasFormMapping) => {
|
||||
this.addFormMapping(aliasFormMapping, modelKey);
|
||||
});
|
||||
} else {
|
||||
this.addFormMapping(formMapping, modelKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} formName
|
||||
* @param {string} modelMapping
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
addFormMapping(formName, modelMapping) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.formMapping, formName)) {
|
||||
console.error(`The form element ${formName} is already mapped to ${this.formMapping[formName]}`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.formMapping[formName] = modelMapping;
|
||||
this.modelMapping[modelMapping] = formName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Component responsible for displaying form popover errors with modified width which is calculated based on the
|
||||
* form group width.
|
||||
*/
|
||||
$(() => {
|
||||
// loads form popover instance
|
||||
$('[data-toggle="form-popover-error"]').popover({
|
||||
html: true,
|
||||
content() {
|
||||
return getErrorContent(this);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Recalculates popover position so it is always aligned horizontally and width is identical
|
||||
* to the child elements of the form.
|
||||
* @param {Object} event
|
||||
*/
|
||||
const repositionPopover = (event) => {
|
||||
const $element = $(event.currentTarget);
|
||||
const $formGroup = $element.closest('.form-group');
|
||||
const $invalidFeedbackContainer = $formGroup.find('.invalid-feedback-container');
|
||||
const $errorPopover = $formGroup.find('.form-popover-error');
|
||||
|
||||
const localeVisibleElementWidth = $invalidFeedbackContainer.width();
|
||||
|
||||
$errorPopover.css('width', localeVisibleElementWidth);
|
||||
|
||||
const horizontalDifference = getHorizontalDifference($invalidFeedbackContainer, $errorPopover);
|
||||
|
||||
$errorPopover.css('left', `${horizontalDifference}px`);
|
||||
};
|
||||
|
||||
/**
|
||||
* gets horizontal difference which helps to align popover horizontally.
|
||||
* @param {jQuery} $invalidFeedbackContainer
|
||||
* @param {jQuery} $errorPopover
|
||||
* @returns {number}
|
||||
*/
|
||||
const getHorizontalDifference = ($invalidFeedbackContainer, $errorPopover) => {
|
||||
const inputHorizontalPosition = $invalidFeedbackContainer.offset().left;
|
||||
const popoverHorizontalPosition = $errorPopover.offset().left;
|
||||
|
||||
return inputHorizontalPosition - popoverHorizontalPosition;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets popover error content pre-fetched in html. It used unique selector to identify which one content to render.
|
||||
*
|
||||
* @param popoverTriggerElement
|
||||
* @returns {jQuery}
|
||||
*/
|
||||
const getErrorContent = (popoverTriggerElement) => {
|
||||
const popoverTriggerId = $(popoverTriggerElement).data('id');
|
||||
|
||||
return $(`.js-popover-error-content[data-id="${popoverTriggerId}"]`).html();
|
||||
};
|
||||
|
||||
// registers the event which displays the popover
|
||||
$(document).on('shown.bs.popover', '[data-toggle="form-popover-error"]', (event) => repositionPopover(event));
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
export default class MultistoreConfigField {
|
||||
constructor() {
|
||||
this.updateMultistoreFieldOnChange();
|
||||
}
|
||||
|
||||
updateMultistoreFieldOnChange() {
|
||||
$(document).on('change', '.multistore-checkbox', function () {
|
||||
const input = $(this).closest('.form-group').find(':input:not(.multistore-checkbox)');
|
||||
const inputContainer = $(this).closest('.form-group').find('.input-container');
|
||||
const labelContainer = $(this).closest('.form-group').find('.form-control-label');
|
||||
const isChecked = $(this).is(':checked');
|
||||
inputContainer.toggleClass('disabled', !isChecked);
|
||||
labelContainer.toggleClass('disabled', !isChecked);
|
||||
input.prop('disabled', !isChecked);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Responsible for opening another page with specified url.
|
||||
* For example used in 'Save and preview' cms page create/edit actions.
|
||||
*
|
||||
* Usage: In selector element attr 'data-preview-url' provide page url.
|
||||
* The page will be opened once provided 'open_preview' parameter in query url
|
||||
*/
|
||||
export default class PreviewOpener {
|
||||
constructor(previewUrlSelector) {
|
||||
this.previewUrl = $(previewUrlSelector).data('preview-url');
|
||||
this.open();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens new page of provided url
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
open() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
|
||||
if (this.previewUrl && urlParams.has('open_preview')) {
|
||||
window.open(this.previewUrl, '_blank');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import {showGrowl} from '@app/utils/growl';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Activates, deactivates, shows, hides submit button inside an input
|
||||
* (depending if input was changed comparing to initial value)
|
||||
* After button is clicked, component fires the callback function which was provided to constructor.
|
||||
*/
|
||||
export default class SubmittableInput {
|
||||
/**
|
||||
* @param {String} wrapperSelector
|
||||
* @param {Function} callback
|
||||
*
|
||||
* @returns {{}}
|
||||
*/
|
||||
constructor(wrapperSelector, callback) {
|
||||
this.inputSelector = '.submittable-input';
|
||||
this.callback = callback;
|
||||
this.wrapperSelector = wrapperSelector;
|
||||
this.buttonSelector = '.check-button';
|
||||
|
||||
this.init();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
init() {
|
||||
const inputs = `${this.wrapperSelector} ${this.inputSelector}`;
|
||||
const that = this;
|
||||
|
||||
$(document).on('focus', inputs, (e) => {
|
||||
this.refreshButtonState(e.currentTarget, true);
|
||||
});
|
||||
$(document).on('input blur', inputs, (e) => {
|
||||
this.refreshButtonState(e.currentTarget);
|
||||
});
|
||||
$(document).on(
|
||||
'click',
|
||||
`${this.wrapperSelector} ${this.buttonSelector}`,
|
||||
function () {
|
||||
that.submitInput(this);
|
||||
},
|
||||
);
|
||||
$(document).on('keyup', inputs, (e) => {
|
||||
if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
const button = this.findButton(e.target);
|
||||
|
||||
this.submitInput(button);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
submitInput(button) {
|
||||
const input = this.findInput(button);
|
||||
|
||||
this.toggleLoading(button, true);
|
||||
|
||||
this.callback(input)
|
||||
.then((response) => {
|
||||
$(input).data('initial-value', input.value);
|
||||
this.toggleButtonVisibility(button, false);
|
||||
|
||||
if (response.message) {
|
||||
showGrowl('success', response.message);
|
||||
}
|
||||
this.toggleLoading(button, false);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toggleError(button, true);
|
||||
this.toggleButtonVisibility(button, false);
|
||||
this.toggleLoading(button, false);
|
||||
|
||||
if (typeof error.responseJSON.errors === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
const messages = error.responseJSON.errors;
|
||||
Object.keys(messages).forEach((key) => {
|
||||
showGrowl('error', messages[key]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} input
|
||||
* @param {Boolean|null} visible
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
refreshButtonState(input, visible = null) {
|
||||
const button = this.findButton(input);
|
||||
const valueWasChanged = this.inputValueChanged(input);
|
||||
this.toggleButtonActivity(button, valueWasChanged);
|
||||
|
||||
if (visible !== null) {
|
||||
this.toggleButtonVisibility(button, visible);
|
||||
} else {
|
||||
this.toggleButtonVisibility(button, valueWasChanged);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} button
|
||||
* @param {Boolean} active
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggleButtonActivity(button, active) {
|
||||
$(button).toggleClass('active', active);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} button
|
||||
* @param {Boolean} visible
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggleButtonVisibility(button, visible) {
|
||||
$(button).toggleClass('d-none', !visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} button
|
||||
* @param {Boolean} visible
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggleLoading(button, loading) {
|
||||
if (loading) {
|
||||
$(button).html('<span class="spinner-border spinner-border-sm"></span>');
|
||||
} else {
|
||||
$(button).html('<i class="material-icons">check</i>');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} button
|
||||
* @param {Boolean} visible
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggleError(button, error) {
|
||||
const input = this.findInput(button);
|
||||
|
||||
$(input).toggleClass('is-invalid', error);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} input
|
||||
*
|
||||
* @returns {HTMLElement}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
findButton(input) {
|
||||
return $(input)
|
||||
.closest(this.wrapperSelector)
|
||||
.find(this.buttonSelector)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} domElement
|
||||
*
|
||||
* @returns {HTMLElement}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
findInput(domElement) {
|
||||
return $(domElement)
|
||||
.closest(this.wrapperSelector)
|
||||
.find(this.inputSelector)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} input
|
||||
*
|
||||
* @returns {Boolean}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
inputValueChanged(input) {
|
||||
const initialValue = $(input).data('initial-value');
|
||||
let newValue = $(input).val();
|
||||
|
||||
if ($(input).hasClass('is-invalid')) {
|
||||
$(input).removeClass('is-invalid');
|
||||
}
|
||||
|
||||
if (typeof initialValue === 'number') {
|
||||
newValue = Number(newValue);
|
||||
}
|
||||
|
||||
return initialValue !== newValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* TextWithLengthCounter handles input with length counter UI.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* There must be an element that wraps both input & counter display with ".js-text-with-length-counter" class.
|
||||
* Counter display must have ".js-countable-text-display" class and input must have ".js-countable-text-input" class.
|
||||
* Text input must have "data-max-length" attribute.
|
||||
*
|
||||
* <div class="js-text-with-length-counter">
|
||||
* <span class="js-countable-text"></span>
|
||||
* <input class="js-countable-input" data-max-length="255">
|
||||
* </div>
|
||||
*
|
||||
* In Javascript you must enable this component:
|
||||
*
|
||||
* new TextWithLengthCounter();
|
||||
*/
|
||||
export default class TextWithLengthCounter {
|
||||
constructor() {
|
||||
this.wrapperSelector = '.js-text-with-length-counter';
|
||||
this.textSelector = '.js-countable-text';
|
||||
this.inputSelector = '.js-countable-input';
|
||||
|
||||
$(document).on('input', `${this.wrapperSelector} ${this.inputSelector}`, (e) => {
|
||||
const $input = $(e.currentTarget);
|
||||
const remainingLength = $input.data('max-length') - $input.val().length;
|
||||
|
||||
$input.closest(this.wrapperSelector).find(this.textSelector).text(remainingLength);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* This component is implemented to work with TextWithRecommendedLengthType,
|
||||
* but can be used as standalone component as well.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* Define your HTML with input and counter. Example:
|
||||
*
|
||||
* <input id="myInput"
|
||||
* class="js-recommended-length-input"
|
||||
* data-recommended-length-counter="#myInput_recommended_length_counter"
|
||||
* >
|
||||
*
|
||||
* <div id"myInput_recommended_length_counter">
|
||||
* <span class="js-current-length">0</span> of 70 characters used (recommended)
|
||||
* </div>
|
||||
*
|
||||
* NOTE: You must use exactly the same Classes, but IDs can be different!
|
||||
*
|
||||
* Then enable component in JavaScript:
|
||||
*
|
||||
* new TextWithRecommendedLengthCounter();
|
||||
*/
|
||||
export default class TextWithRecommendedLengthCounter {
|
||||
constructor() {
|
||||
$(document).on('input', '.js-recommended-length-input', (event) => {
|
||||
const $input = $(event.currentTarget);
|
||||
|
||||
$($input.data('recommended-length-counter')).find('.js-current-length').text($input.val().length);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Component responsible for filtering select values by language selected.
|
||||
*/
|
||||
export default class TranslatableChoice {
|
||||
constructor() {
|
||||
// registers the event which displays the popover
|
||||
$(document).on('change', 'select.translatable_choice_language', (event) => {
|
||||
this.filterSelect(event);
|
||||
});
|
||||
|
||||
$('select.translatable_choice_language').trigger('change');
|
||||
}
|
||||
|
||||
filterSelect(event) {
|
||||
const $element = $(event.currentTarget);
|
||||
const $formGroup = $element.closest('.form-group');
|
||||
const language = $element.find('option:selected').val();
|
||||
|
||||
// show all the languages selects
|
||||
$formGroup.find(`select.translatable_choice[data-language="${language}"]`).parent().show();
|
||||
|
||||
const $selects = $formGroup.find('select.translatable_choice');
|
||||
|
||||
// Hide all the selects not corresponding to the language selected
|
||||
$selects.not(`select.translatable_choice[data-language="${language}"]`).each((index, item) => {
|
||||
$(item).parent().hide();
|
||||
});
|
||||
|
||||
// Bind choice selection to fill the hidden input
|
||||
this.bindValueSelection($selects);
|
||||
}
|
||||
|
||||
bindValueSelection($selects) {
|
||||
$selects.each((index, element) => {
|
||||
$(element).on('change', (event) => {
|
||||
const $select = $(event.currentTarget);
|
||||
const selectId = $select.attr('id');
|
||||
$(`#${selectId}_value`).val($select.find('option:selected').val());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generates random values for inputs.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* There should be a button in HTML with 2 required data-* properties:
|
||||
* 1. data-target-input-id - input id for which value should be generated
|
||||
* 2. data-generated-value-size -
|
||||
*
|
||||
* Example button: <button class="js-generator-btn"
|
||||
* data-target-input-id="my-input-id"
|
||||
* data-generated-value-length="16"
|
||||
* >
|
||||
* Generate!
|
||||
* </button>
|
||||
*
|
||||
* In JavaScript you have to enable this functionality using GeneratableInput component like so:
|
||||
*
|
||||
* const generateableInput = new GeneratableInput();
|
||||
* generateableInput.attachOn('.js-generator-btn'); // every time our button is clicked
|
||||
* // it will generate random value of 16 characters
|
||||
* // for input with id of "my-input-id"
|
||||
*
|
||||
* You can attach as many different buttons as you like using "attachOn()" function
|
||||
* as long as 2 required data-* attributes are present at each button.
|
||||
*/
|
||||
export default class GeneratableInput {
|
||||
constructor() {
|
||||
return {
|
||||
attachOn: (btnSelector) => this.attachOn(btnSelector),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches event listener on button than can generate value
|
||||
*
|
||||
* @param {String} generatorBtnSelector
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
attachOn(generatorBtnSelector) {
|
||||
const generatorBtn = document.querySelector(generatorBtnSelector);
|
||||
|
||||
if (generatorBtn !== null) {
|
||||
generatorBtn.addEventListener('click', (event) => {
|
||||
const {attributes} = event.currentTarget;
|
||||
|
||||
const targetInputId = attributes.getNamedItem('data-target-input-id').value;
|
||||
const generatedValueLength = parseInt(attributes.getNamedItem('data-generated-value-length').value, 10);
|
||||
|
||||
const targetInput = document.querySelector(`#${targetInputId}`);
|
||||
targetInput.value = this.generateValue(generatedValueLength);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates random value for input
|
||||
*
|
||||
* @param {Number} length
|
||||
*
|
||||
* @returns {string}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
generateValue(length) {
|
||||
const chars = '123456789ABCDEFGHIJKLMNPQRSTUVWXYZ';
|
||||
let generatedValue = '';
|
||||
|
||||
for (let i = 1; i <= length; i += 1) {
|
||||
generatedValue += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
|
||||
return generatedValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class DeleteCategoriesBulkActionExtension handles submitting of row action
|
||||
*/
|
||||
export default class DeleteCategoriesBulkActionExtension {
|
||||
constructor() {
|
||||
return {
|
||||
extend: (grid) => this.extend(grid),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
grid.getContainer().on('click', '.js-delete-categories-bulk-action', (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const submitUrl = $(event.currentTarget).data('categories-delete-url');
|
||||
|
||||
const $deleteCategoriesModal = $(`#${grid.getId()}_grid_delete_categories_modal`);
|
||||
$deleteCategoriesModal.modal('show');
|
||||
|
||||
$deleteCategoriesModal.on('click', '.js-submit-delete-categories', () => {
|
||||
const $checkboxes = grid.getContainer().find('.js-bulk-action-checkbox:checked');
|
||||
const $categoriesToDeleteInputBlock = $('#delete_categories_categories_to_delete');
|
||||
|
||||
$checkboxes.each((i, element) => {
|
||||
const $checkbox = $(element);
|
||||
|
||||
const categoryInput = $categoriesToDeleteInputBlock
|
||||
.data('prototype')
|
||||
.replace(/__name__/g, $checkbox.val());
|
||||
|
||||
const $input = $($.parseHTML(categoryInput)[0]);
|
||||
$input.val($checkbox.val());
|
||||
|
||||
$categoriesToDeleteInputBlock.append($input);
|
||||
});
|
||||
|
||||
const $form = $deleteCategoriesModal.find('form');
|
||||
|
||||
$form.attr('action', submitUrl);
|
||||
$form.submit();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Handles bulk delete for "Customers" grid.
|
||||
*/
|
||||
export default class DeleteCustomersBulkActionExtension {
|
||||
constructor() {
|
||||
return {
|
||||
extend: (grid) => this.extend(grid),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
grid.getContainer().on('click', '.js-delete-customers-bulk-action', (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const submitUrl = $(event.currentTarget).data('customers-delete-url');
|
||||
|
||||
const $modal = $(`#${grid.getId()}_grid_delete_customers_modal`);
|
||||
$modal.modal('show');
|
||||
|
||||
$modal.on('click', '.js-submit-delete-customers', () => {
|
||||
const $selectedCustomerCheckboxes = grid.getContainer().find('.js-bulk-action-checkbox:checked');
|
||||
|
||||
$selectedCustomerCheckboxes.each((i, checkbox) => {
|
||||
const $input = $(checkbox);
|
||||
|
||||
this.addCustomerToDeleteCollectionInput($input.val());
|
||||
});
|
||||
|
||||
const $form = $modal.find('form');
|
||||
|
||||
$form.attr('action', submitUrl);
|
||||
$form.submit();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create input with customer id and add it to delete collection input
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
addCustomerToDeleteCollectionInput(customerId) {
|
||||
const $customersInput = $('#delete_customers_customers_to_delete');
|
||||
|
||||
const customerInput = $customersInput
|
||||
.data('prototype')
|
||||
.replace(/__name__/g, customerId);
|
||||
const $item = $($.parseHTML(customerInput)[0]);
|
||||
$item.val(customerId);
|
||||
|
||||
$customersInput.append($item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class CategoryDeleteRowActionExtension handles submitting of row action
|
||||
*/
|
||||
export default class DeleteCategoryRowActionExtension {
|
||||
constructor() {
|
||||
return {
|
||||
extend: (grid) => this.extend(grid),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
grid.getContainer().on('click', '.js-delete-category-row-action', (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const $deleteCategoriesModal = $(`#${grid.getId()}_grid_delete_categories_modal`);
|
||||
$deleteCategoriesModal.modal('show');
|
||||
|
||||
$deleteCategoriesModal.on('click', '.js-submit-delete-categories', () => {
|
||||
const $button = $(event.currentTarget);
|
||||
const categoryId = $button.data('category-id');
|
||||
|
||||
const $categoriesToDeleteInputBlock = $('#delete_categories_categories_to_delete');
|
||||
|
||||
const categoryInput = $categoriesToDeleteInputBlock
|
||||
.data('prototype')
|
||||
.replace(/__name__/g, $categoriesToDeleteInputBlock.children().length);
|
||||
|
||||
const $item = $($.parseHTML(categoryInput)[0]);
|
||||
$item.val(categoryId);
|
||||
|
||||
$categoriesToDeleteInputBlock.append($item);
|
||||
|
||||
const $form = $deleteCategoriesModal.find('form');
|
||||
|
||||
$form.attr('action', $button.data('category-delete-url'));
|
||||
$form.submit();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class DeleteCustomerRowActionExtension handles submitting of row action
|
||||
*/
|
||||
export default class DeleteCustomerRowActionExtension {
|
||||
constructor() {
|
||||
return {
|
||||
extend: (grid) => this.extend(grid),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
grid.getContainer().on('click', '.js-delete-customer-row-action', (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const $deleteCustomersModal = $(`#${grid.getId()}_grid_delete_customers_modal`);
|
||||
$deleteCustomersModal.modal('show');
|
||||
|
||||
$deleteCustomersModal.on('click', '.js-submit-delete-customers', () => {
|
||||
const $button = $(event.currentTarget);
|
||||
const customerId = $button.data('customer-id');
|
||||
|
||||
this.addCustomerInput(customerId);
|
||||
|
||||
const $form = $deleteCustomersModal.find('form');
|
||||
|
||||
$form.attr('action', $button.data('customer-delete-url'));
|
||||
$form.submit();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds input for selected customer to delete form
|
||||
*
|
||||
* @param {integer} customerId
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
addCustomerInput(customerId) {
|
||||
const $customersToDeleteInputBlock = $('#delete_customers_customers_to_delete');
|
||||
|
||||
const customerInput = $customersToDeleteInputBlock
|
||||
.data('prototype')
|
||||
.replace(/__name__/g, $customersToDeleteInputBlock.children().length);
|
||||
|
||||
const $item = $($.parseHTML(customerInput)[0]);
|
||||
$item.val(customerId);
|
||||
|
||||
$customersToDeleteInputBlock.append($item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import ConfirmModal from '@components/modal';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class SubmitRowActionExtension handles submitting of row action
|
||||
*/
|
||||
export default class SubmitRowActionExtension {
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
grid.getContainer().on('click', '.js-submit-row-action', (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const $button = $(event.currentTarget);
|
||||
const confirmMessage = $button.data('confirmMessage');
|
||||
const confirmTitle = $button.data('title');
|
||||
|
||||
const method = $button.data('method');
|
||||
|
||||
if (confirmTitle) {
|
||||
this.showConfirmModal($button, grid, confirmMessage, confirmTitle, method);
|
||||
} else {
|
||||
if (confirmMessage.length && !window.confirm(confirmMessage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.postForm($button, method);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
postForm($button, method) {
|
||||
const isGetOrPostMethod = ['GET', 'POST'].includes(method);
|
||||
|
||||
const $form = $('<form>', {
|
||||
action: $button.data('url'),
|
||||
method: isGetOrPostMethod ? method : 'POST',
|
||||
}).appendTo('body');
|
||||
|
||||
if (!isGetOrPostMethod) {
|
||||
$form.append($('<input>', {
|
||||
type: '_hidden',
|
||||
name: '_method',
|
||||
value: method,
|
||||
}));
|
||||
}
|
||||
|
||||
$form.submit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {jQuery} $submitBtn
|
||||
* @param {Grid} grid
|
||||
* @param {string} confirmMessage
|
||||
* @param {string} confirmTitle
|
||||
* @param {string} method
|
||||
*/
|
||||
showConfirmModal($submitBtn, grid, confirmMessage, confirmTitle, method) {
|
||||
const confirmButtonLabel = $submitBtn.data('confirmButtonLabel');
|
||||
const closeButtonLabel = $submitBtn.data('closeButtonLabel');
|
||||
const confirmButtonClass = $submitBtn.data('confirmButtonClass');
|
||||
|
||||
const modal = new ConfirmModal({
|
||||
id: `${grid.getId()}-grid-confirm-modal`,
|
||||
confirmTitle,
|
||||
confirmMessage,
|
||||
confirmButtonLabel,
|
||||
closeButtonLabel,
|
||||
confirmButtonClass,
|
||||
}, () => this.postForm($submitBtn, method));
|
||||
|
||||
modal.show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class BulkActionSelectCheckboxExtension
|
||||
*/
|
||||
export default class BulkActionCheckboxExtension {
|
||||
/**
|
||||
* Extend grid with bulk action checkboxes handling functionality
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
this.handleBulkActionCheckboxSelect(grid);
|
||||
this.handleBulkActionSelectAllCheckbox(grid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles "Select all" button in the grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
handleBulkActionSelectAllCheckbox(grid) {
|
||||
grid.getContainer().on('change', '.js-bulk-action-select-all', (e) => {
|
||||
const $checkbox = $(e.currentTarget);
|
||||
|
||||
const isChecked = $checkbox.is(':checked');
|
||||
|
||||
if (isChecked) {
|
||||
this.enableBulkActionsBtn(grid);
|
||||
} else {
|
||||
this.disableBulkActionsBtn(grid);
|
||||
}
|
||||
|
||||
grid.getContainer().find('.js-bulk-action-checkbox').prop('checked', isChecked);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles each bulk action checkbox select in the grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
handleBulkActionCheckboxSelect(grid) {
|
||||
grid.getContainer().on('change', '.js-bulk-action-checkbox', () => {
|
||||
const checkedRowsCount = grid.getContainer().find('.js-bulk-action-checkbox:checked').length;
|
||||
|
||||
if (checkedRowsCount > 0) {
|
||||
this.enableBulkActionsBtn(grid);
|
||||
} else {
|
||||
this.disableBulkActionsBtn(grid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable bulk actions button
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
enableBulkActionsBtn(grid) {
|
||||
grid.getContainer().find('.js-bulk-actions-btn').prop('disabled', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable bulk actions button
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
disableBulkActionsBtn(grid) {
|
||||
grid.getContainer().find('.js-bulk-actions-btn').prop('disabled', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
import Router from '../../router';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class BulkOpenTabsExtension
|
||||
*/
|
||||
export default class BulkOpenTabsExtension {
|
||||
constructor() {
|
||||
this.router = new Router();
|
||||
return {
|
||||
extend: (grid) => this.extend(grid),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend grid with bulk action open tabs
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
grid.getContainer().on('click', '.js-bulk-action-btn.open_tabs', (event) => {
|
||||
this.openTabs(event, grid);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle bulk action opening tabs
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Grid} grid
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
openTabs(event, grid) {
|
||||
const $submitBtn = $(event.currentTarget);
|
||||
const route = $submitBtn.data('route');
|
||||
const routeParamName = $submitBtn.data('routeParamName');
|
||||
const tabsBlockedMessage = $submitBtn.data('tabsBlockedMessage');
|
||||
|
||||
const $checkboxes = grid.getContainer().find('.js-bulk-action-checkbox:checked');
|
||||
let allTabsOpened = true;
|
||||
$checkboxes.each((i, element) => {
|
||||
const $checkbox = $(element);
|
||||
const routeParams = {};
|
||||
routeParams[routeParamName] = $checkbox.val();
|
||||
|
||||
const handle = window.open(this.router.generate(route, routeParams));
|
||||
|
||||
if (handle) {
|
||||
handle.blur();
|
||||
window.focus();
|
||||
} else {
|
||||
allTabsOpened = false;
|
||||
}
|
||||
|
||||
if (!allTabsOpened) {
|
||||
alert(tabsBlockedMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* This extension enables submit functionality of the choice fields in grid.
|
||||
*
|
||||
* Usage of the extension:
|
||||
*
|
||||
* const myGrid = new Grid('myGrid');
|
||||
* myGrid.addExtension(new ChoiceExtension());
|
||||
*
|
||||
*/
|
||||
export default class ChoiceExtension {
|
||||
constructor() {
|
||||
this.locks = [];
|
||||
}
|
||||
|
||||
extend(grid) {
|
||||
const $choiceOptionsContainer = grid.getContainer().find('table.table .js-choice-options');
|
||||
|
||||
$choiceOptionsContainer.find('.js-dropdown-item').on('click', (e) => {
|
||||
e.preventDefault();
|
||||
const $button = $(e.currentTarget);
|
||||
const $parent = $button.closest('.js-choice-options');
|
||||
const url = $parent.data('url');
|
||||
|
||||
this.submitForm(url, $button);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the form.
|
||||
* @param {string} url
|
||||
* @param {jQuery} $button
|
||||
* @private
|
||||
*/
|
||||
submitForm(url, $button) {
|
||||
const selectedStatusId = $button.data('value');
|
||||
|
||||
if (this.isLocked(url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $form = $('<form>', {
|
||||
action: url,
|
||||
method: 'POST',
|
||||
}).append(
|
||||
$('<input>', {
|
||||
name: 'value',
|
||||
value: selectedStatusId,
|
||||
type: 'hidden',
|
||||
}));
|
||||
|
||||
$form.appendTo('body');
|
||||
$form.submit();
|
||||
|
||||
this.lock(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if current url is being used at the moment.
|
||||
*
|
||||
* @param url
|
||||
* @return {boolean}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
isLocked(url) {
|
||||
return this.locks.includes(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks the current url so it cant be used twice to execute same request
|
||||
* @param url
|
||||
* @private
|
||||
*/
|
||||
lock(url) {
|
||||
this.locks.push(url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class ReloadListExtension extends grid with "Column toggling" feature
|
||||
*/
|
||||
export default class ColumnTogglingExtension {
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
const $table = grid.getContainer().find('table.table');
|
||||
$table.find('.ps-togglable-row').on('click', (e) => {
|
||||
e.preventDefault();
|
||||
this.toggleValue($(e.delegateTarget));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {jQuery} row
|
||||
* @private
|
||||
*/
|
||||
toggleValue(row) {
|
||||
const toggleUrl = row.data('toggleUrl');
|
||||
|
||||
this.submitAsForm(toggleUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits request url as form
|
||||
*
|
||||
* @param {string} toggleUrl
|
||||
* @private
|
||||
*/
|
||||
submitAsForm(toggleUrl) {
|
||||
const $form = $('<form>', {
|
||||
action: toggleUrl,
|
||||
method: 'POST',
|
||||
}).appendTo('body');
|
||||
|
||||
$form.submit();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import 'tablednd/dist/jquery.tablednd.min';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class CategoryPositionExtension extends Grid with reorderable category positions
|
||||
*/
|
||||
export default class CategoryPositionExtension {
|
||||
constructor() {
|
||||
return {
|
||||
extend: (grid) => this.extend(grid),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
this.grid = grid;
|
||||
|
||||
this.addIdsToGridTableRows();
|
||||
|
||||
grid.getContainer().find('.js-grid-table').tableDnD({
|
||||
dragHandle: '.js-drag-handle',
|
||||
onDragClass: 'dragging-row',
|
||||
onDragStart: () => {
|
||||
this.originalPositions = decodeURIComponent($.tableDnD.serialize());
|
||||
},
|
||||
onDrop: (table, row) => this.handleCategoryPositionChange(row),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* When position is changed handle update
|
||||
*
|
||||
* @param {HTMLElement} row
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
handleCategoryPositionChange(row) {
|
||||
const positions = decodeURIComponent($.tableDnD.serialize());
|
||||
const way = (this.originalPositions.indexOf(row.id) < positions.indexOf(row.id)) ? 1 : 0;
|
||||
|
||||
const $categoryPositionContainer = $(row).find(`.js-${this.grid.getId()}-position:first`);
|
||||
|
||||
const categoryId = $categoryPositionContainer.data('id');
|
||||
const categoryParentId = $categoryPositionContainer.data('id-parent');
|
||||
const positionUpdateUrl = $categoryPositionContainer.data('position-update-url');
|
||||
|
||||
let params = positions.replace(new RegExp(`${this.grid.getId()}_grid_table`, 'g'), 'positions');
|
||||
|
||||
const queryParams = {
|
||||
id_category_parent: categoryParentId,
|
||||
id_category_to_move: categoryId,
|
||||
way,
|
||||
};
|
||||
|
||||
if (positions.indexOf('_0&') !== -1) {
|
||||
queryParams.found_first = 1;
|
||||
}
|
||||
|
||||
params += `&${$.param(queryParams)}`;
|
||||
|
||||
this.updateCategoryPosition(positionUpdateUrl, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ID's to Grid table rows to make tableDnD.onDrop() function work.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
addIdsToGridTableRows() {
|
||||
this.grid.getContainer()
|
||||
.find('.js-grid-table')
|
||||
.find(`.js-${this.grid.getId()}-position`)
|
||||
.each((index, positionWrapper) => {
|
||||
const $positionWrapper = $(positionWrapper);
|
||||
|
||||
const categoryId = $positionWrapper.data('id');
|
||||
const categoryParentId = $positionWrapper.data('id-parent');
|
||||
const position = $positionWrapper.data('position');
|
||||
|
||||
const id = `tr_${categoryParentId}_${categoryId}_${position}`;
|
||||
|
||||
$positionWrapper.closest('tr').attr('id', id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update categories listing with new positions
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
updateCategoryIdsAndPositions() {
|
||||
this.grid.getContainer()
|
||||
.find('.js-grid-table')
|
||||
.find(`.js-${this.grid.getId()}-position`)
|
||||
.each((index, positionWrapper) => {
|
||||
const $positionWrapper = $(positionWrapper);
|
||||
const $row = $positionWrapper.closest('tr');
|
||||
|
||||
const offset = $positionWrapper.data('pagination-offset');
|
||||
const newPosition = offset > 0 ? index + offset : index;
|
||||
|
||||
const oldId = $row.attr('id');
|
||||
$row.attr('id', oldId.replace(/_[0-9]$/g, `_${newPosition}`));
|
||||
|
||||
$positionWrapper.find('.js-position').text(newPosition + 1);
|
||||
$positionWrapper.data('position', newPosition);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Process categories positions update
|
||||
*
|
||||
* @param {String} url
|
||||
* @param {String} params
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
updateCategoryPosition(url, params) {
|
||||
$.post({
|
||||
url,
|
||||
headers: {
|
||||
'cache-control': 'no-cache',
|
||||
},
|
||||
data: params,
|
||||
dataType: 'json',
|
||||
}).then((response) => {
|
||||
if (response.success) {
|
||||
window.showSuccessMessage(response.message);
|
||||
} else {
|
||||
window.showErrorMessage(response.message);
|
||||
}
|
||||
|
||||
this.updateCategoryIdsAndPositions();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class AsyncToggleColumnExtension submits toggle action using AJAX
|
||||
*/
|
||||
export default class AsyncToggleColumnExtension {
|
||||
constructor() {
|
||||
return {
|
||||
extend: (grid) => this.extend(grid),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
grid
|
||||
.getContainer()
|
||||
.find('.js-grid-table')
|
||||
.on('click', '.ps-togglable-row', (event) => {
|
||||
const $button = $(event.currentTarget);
|
||||
|
||||
if (!$button.hasClass('ps-switch')) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
$.post({
|
||||
url: $button.data('toggle-url'),
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status) {
|
||||
window.showSuccessMessage(response.message);
|
||||
|
||||
this.toggleButtonDisplay($button);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
window.showErrorMessage(response.message);
|
||||
})
|
||||
.catch((error) => {
|
||||
const response = error.responseJSON;
|
||||
|
||||
window.showErrorMessage(response.message);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle button display from enabled to disabled and other way around
|
||||
*
|
||||
* @param {jQuery} $button
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggleButtonDisplay($button) {
|
||||
const isActive = $button.hasClass('grid-toggler-icon-valid');
|
||||
|
||||
const classToAdd = isActive ? 'grid-toggler-icon-not-valid' : 'grid-toggler-icon-valid';
|
||||
const classToRemove = isActive ? 'grid-toggler-icon-valid' : 'grid-toggler-icon-not-valid';
|
||||
const icon = isActive ? 'clear' : 'check';
|
||||
|
||||
$button.removeClass(classToRemove);
|
||||
$button.addClass(classToAdd);
|
||||
|
||||
if ($button.hasClass('material-icons')) {
|
||||
$button.text(icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class ExportToSqlManagerExtension extends grid with exporting query to SQL Manager
|
||||
*/
|
||||
export default class ExportToSqlManagerExtension {
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
grid.getHeaderContainer().on('click', '.js-common_show_query-grid-action', () => this.onShowSqlQueryClick(grid));
|
||||
grid.getHeaderContainer().on(
|
||||
'click',
|
||||
'.js-common_export_sql_manager-grid-action',
|
||||
() => this.onExportSqlManagerClick(grid),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when clicking on the "show sql query" toolbar button
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
onShowSqlQueryClick(grid) {
|
||||
const $sqlManagerForm = $(`#${grid.getId()}_common_show_query_modal_form`);
|
||||
this.fillExportForm($sqlManagerForm, grid);
|
||||
|
||||
const $modal = $(`#${grid.getId()}_grid_common_show_query_modal`);
|
||||
$modal.modal('show');
|
||||
|
||||
$modal.on('click', '.btn-sql-submit', () => $sqlManagerForm.submit());
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when clicking on the "export to the sql query" toolbar button
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
onExportSqlManagerClick(grid) {
|
||||
const $sqlManagerForm = $(`#${grid.getId()}_common_show_query_modal_form`);
|
||||
|
||||
this.fillExportForm($sqlManagerForm, grid);
|
||||
|
||||
$sqlManagerForm.submit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill export form with SQL and it's name
|
||||
*
|
||||
* @param {jQuery} $sqlManagerForm
|
||||
* @param {Grid} grid
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
fillExportForm($sqlManagerForm, grid) {
|
||||
const query = grid.getContainer().find('.js-grid-table').data('query');
|
||||
|
||||
$sqlManagerForm.find('textarea[name="sql"]').val(query);
|
||||
$sqlManagerForm.find('input[name="name"]').val(this.getNameFromBreadcrumb());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get export name from page's breadcrumb
|
||||
*
|
||||
* @return {String}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
getNameFromBreadcrumb() {
|
||||
const $breadcrumbs = $('.header-toolbar').find('.breadcrumb-item');
|
||||
let name = '';
|
||||
|
||||
$breadcrumbs.each((i, item) => {
|
||||
const $breadcrumb = $(item);
|
||||
|
||||
const breadcrumbTitle = $breadcrumb.find('a').length > 0
|
||||
? $breadcrumb.find('a').text()
|
||||
: $breadcrumb.text();
|
||||
|
||||
if (name.length > 0) {
|
||||
name = name.concat(' > ');
|
||||
}
|
||||
|
||||
name = name.concat(breadcrumbTitle);
|
||||
});
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import resetSearch from '@app/utils/reset_search';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class FiltersResetExtension extends grid with filters resetting
|
||||
*/
|
||||
export default class FiltersResetExtension {
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
grid.getContainer().on('click', '.js-reset-search', (event) => {
|
||||
resetSearch($(event.currentTarget).data('url'), $(event.currentTarget).data('redirect'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Responsible for grid filters search and reset button availability when filter inputs changes.
|
||||
*/
|
||||
export default class FiltersSubmitButtonEnablerExtension {
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
const $filtersRow = grid.getContainer().find('.column-filters');
|
||||
$filtersRow.find('.grid-search-button').prop('disabled', true);
|
||||
|
||||
$filtersRow.find('input:not(.js-bulk-action-select-all), select').on('input dp.change', () => {
|
||||
$filtersRow.find('.grid-search-button').prop('disabled', false);
|
||||
$filtersRow.find('.js-grid-reset-button').prop('hidden', false);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class LinkRowActionExtension handles link row actions
|
||||
*/
|
||||
export default class LinkRowActionExtension {
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
this.initRowLinks(grid);
|
||||
this.initConfirmableActions(grid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
initConfirmableActions(grid) {
|
||||
grid.getContainer().on('click', '.js-link-row-action', (event) => {
|
||||
const confirmMessage = $(event.currentTarget).data('confirm-message');
|
||||
|
||||
if (confirmMessage.length && !window.confirm(confirmMessage)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a click event on rows that matches the first link action (if present)
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
initRowLinks(grid) {
|
||||
$('tr', grid.getContainer()).each(function initEachRow() {
|
||||
const $parentRow = $(this);
|
||||
|
||||
$('.js-link-row-action[data-clickable-row=1]:first', $parentRow).each(function propagateFirstLinkAction() {
|
||||
const $rowAction = $(this);
|
||||
const $parentCell = $rowAction.closest('td');
|
||||
|
||||
const clickableCells = $('td.clickable', $parentRow).not($parentCell);
|
||||
let isDragging = false;
|
||||
clickableCells.addClass('cursor-pointer').mousedown(() => {
|
||||
$(window).mousemove(() => {
|
||||
isDragging = true;
|
||||
$(window).unbind('mousemove');
|
||||
});
|
||||
});
|
||||
|
||||
clickableCells.mouseup(() => {
|
||||
const wasDragging = isDragging;
|
||||
isDragging = false;
|
||||
$(window).unbind('mousemove');
|
||||
|
||||
if (!wasDragging) {
|
||||
const confirmMessage = $rowAction.data('confirm-message');
|
||||
|
||||
if (!confirmMessage.length || window.confirm(confirmMessage)) {
|
||||
document.location = $rowAction.attr('href');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Allows submitting form inside modals.
|
||||
* Form must be inside modal, see example structure below:
|
||||
*
|
||||
* <div class="modal" id="uniqueModalId">
|
||||
* <form data-bulk-inputs-id="bulkInputs">
|
||||
* <div class="d-none">
|
||||
* <div id="bulkInputs" data-prototype="<input type="hidden" name="__name__"/>"></div>
|
||||
* </div>
|
||||
* </form>
|
||||
* </div>
|
||||
*
|
||||
* Note that "data-prototype" is required to add checked items to the form. "__name__"
|
||||
* will be replaced with value of bulk checkbox.
|
||||
*/
|
||||
export default class ModalFormSubmitExtension {
|
||||
extend(grid) {
|
||||
grid.getContainer().on('click', '.js-bulk-modal-form-submit-btn', (event) => {
|
||||
const modalId = $(event.target).data('modal-id');
|
||||
|
||||
const $modal = $(`#${modalId}`);
|
||||
$modal.modal('show');
|
||||
|
||||
$modal.find('.js-submit-modal-form-btn').on('click', () => {
|
||||
const $form = $modal.find('form');
|
||||
const $bulkInputsBlock = $form.find(`#${$form.data('bulk-inputs-id')}`);
|
||||
const $checkboxes = grid.getContainer().find('.js-bulk-action-checkbox:checked');
|
||||
|
||||
$checkboxes.each((i, element) => {
|
||||
const $checkbox = $(element);
|
||||
|
||||
const input = $bulkInputsBlock
|
||||
.data('prototype')
|
||||
.replace(/__name__/g, $checkbox.val());
|
||||
|
||||
const $input = $($.parseHTML(input)[0]);
|
||||
$input.val($checkbox.val());
|
||||
|
||||
$form.append($input);
|
||||
});
|
||||
|
||||
$form.submit();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import 'tablednd/dist/jquery.tablednd.min';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class PositionExtension extends Grid with reorderable positions
|
||||
*/
|
||||
export default class PositionExtension {
|
||||
constructor() {
|
||||
return {
|
||||
extend: (grid) => this.extend(grid),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
this.grid = grid;
|
||||
this.addIdsToGridTableRows();
|
||||
grid.getContainer().find('.js-grid-table').tableDnD({
|
||||
onDragClass: 'position-row-while-drag',
|
||||
dragHandle: '.js-drag-handle',
|
||||
onDrop: (table, row) => this.handlePositionChange(row),
|
||||
});
|
||||
grid.getContainer().find('.js-drag-handle').hover(
|
||||
function () {
|
||||
$(this).closest('tr').addClass('hover');
|
||||
},
|
||||
function () {
|
||||
$(this).closest('tr').removeClass('hover');
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* When position is changed handle update
|
||||
*
|
||||
* @param {HTMLElement} row
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
handlePositionChange(row) {
|
||||
const $rowPositionContainer = $(row).find(`.js-${this.grid.getId()}-position:first`);
|
||||
const updateUrl = $rowPositionContainer.data('update-url');
|
||||
const method = $rowPositionContainer.data('update-method');
|
||||
const positions = this.getRowsPositions();
|
||||
const params = {positions};
|
||||
|
||||
this.updatePosition(updateUrl, params, method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current table positions
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
getRowsPositions() {
|
||||
const tableData = JSON.parse($.tableDnD.jsonize());
|
||||
const rowsData = tableData[`${this.grid.getId()}_grid_table`];
|
||||
const completeRowsData = [];
|
||||
|
||||
let trData;
|
||||
|
||||
// retrieve dragAndDropOffset offset to have all needed data
|
||||
// for positions mapping evolution over time
|
||||
for (let i = 0; i < rowsData.length; i += 1) {
|
||||
trData = this.grid.getContainer()
|
||||
.find(`#${rowsData[i]}`);
|
||||
|
||||
completeRowsData.push({
|
||||
rowMarker: rowsData[i],
|
||||
offset: trData.data('dragAndDropOffset'),
|
||||
});
|
||||
}
|
||||
|
||||
return this.computeMappingBetweenOldAndNewPositions(completeRowsData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ID's to Grid table rows to make tableDnD.onDrop() function work.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
addIdsToGridTableRows() {
|
||||
let counter = 0;
|
||||
|
||||
this.grid.getContainer()
|
||||
.find(`.js-grid-table .js-${this.grid.getId()}-position`)
|
||||
.each((index, positionWrapper) => {
|
||||
const $positionWrapper = $(positionWrapper);
|
||||
const rowId = $positionWrapper.data('id');
|
||||
const position = $positionWrapper.data('position');
|
||||
const id = `row_${rowId}_${position}`;
|
||||
$positionWrapper.closest('tr').attr('id', id);
|
||||
$positionWrapper.closest('td').addClass('js-drag-handle');
|
||||
$positionWrapper.closest('tr').data('dragAndDropOffset', counter);
|
||||
|
||||
counter += 1;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Process rows positions update
|
||||
*
|
||||
* @param {String} url
|
||||
* @param {Object} params
|
||||
* @param {String} method
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
updatePosition(url, params, method) {
|
||||
const isGetOrPostMethod = ['GET', 'POST'].includes(method);
|
||||
|
||||
const $form = $('<form>', {
|
||||
action: url,
|
||||
method: isGetOrPostMethod ? method : 'POST',
|
||||
}).appendTo('body');
|
||||
|
||||
const positionsNb = params.positions.length;
|
||||
let position;
|
||||
|
||||
for (let i = 0; i < positionsNb; i += 1) {
|
||||
position = params.positions[i];
|
||||
$form.append(
|
||||
$('<input>', {
|
||||
type: 'hidden',
|
||||
name: `positions[${i}][rowId]`,
|
||||
value: position.rowId,
|
||||
}),
|
||||
$('<input>', {
|
||||
type: 'hidden',
|
||||
name: `positions[${i}][oldPosition]`,
|
||||
value: position.oldPosition,
|
||||
}),
|
||||
$('<input>', {
|
||||
type: 'hidden',
|
||||
name: `positions[${i}][newPosition]`,
|
||||
value: position.newPosition,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// This _method param is used by Symfony to simulate DELETE and PUT methods
|
||||
if (!isGetOrPostMethod) {
|
||||
$form.append($('<input>', {
|
||||
type: 'hidden',
|
||||
name: '_method',
|
||||
value: method,
|
||||
}));
|
||||
}
|
||||
|
||||
$form.submit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rows have been reordered. This function
|
||||
* finds, for each row ID: the old position, the new position
|
||||
*
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
computeMappingBetweenOldAndNewPositions(rowsData) {
|
||||
const regex = /^row_(\d+)_(\d+)$/;
|
||||
const mapping = Array(rowsData.length).fill().map(Object);
|
||||
|
||||
for (let i = 0; i < rowsData.length; i += 1) {
|
||||
const [, rowId, oldPosition] = regex.exec(rowsData[i].rowMarker);
|
||||
mapping[i].rowId = rowId;
|
||||
mapping[i].oldPosition = parseInt(oldPosition, 10);
|
||||
// This row will have as a new position the old position of the current one
|
||||
mapping[rowsData[i].offset].newPosition = mapping[i].oldPosition;
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Extends grid with preview functionality.
|
||||
*/
|
||||
export default class PreviewExtension {
|
||||
constructor(previewCustomization) {
|
||||
this.locks = [];
|
||||
this.expandSelector = '.js-expand';
|
||||
this.collapseSelector = '.js-collapse';
|
||||
this.previewOpenClass = 'preview-open';
|
||||
this.previewToggleSelector = '.preview-toggle';
|
||||
this.previewCustomization = previewCustomization;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends provided grid with preview functionality
|
||||
*
|
||||
* @param grid
|
||||
*/
|
||||
extend(grid) {
|
||||
this.$gridContainer = $(grid.getContainer);
|
||||
|
||||
this.$gridContainer.find('tbody tr').on('mouseover mouseleave', (event) => this.handleIconHovering(event));
|
||||
this.$gridContainer.find(this.previewToggleSelector).on('click', (event) => this.togglePreview(event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows/hides preview toggling icons
|
||||
*
|
||||
* @param event
|
||||
* @private
|
||||
*/
|
||||
handleIconHovering(event) {
|
||||
const $previewToggle = $(event.currentTarget).find(this.previewToggleSelector);
|
||||
|
||||
if (event.type === 'mouseover' && !$(event.currentTarget).hasClass(this.previewOpenClass)) {
|
||||
this.showExpandIcon($previewToggle);
|
||||
} else {
|
||||
this.hideExpandIcon($previewToggle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows/hides preview
|
||||
*
|
||||
* @param event
|
||||
* @private
|
||||
*/
|
||||
togglePreview(event) {
|
||||
const $previewToggle = $(event.currentTarget);
|
||||
const $columnRow = $previewToggle.closest('tr');
|
||||
|
||||
if ($columnRow.hasClass(this.previewOpenClass)) {
|
||||
$columnRow.next('.preview-row').remove();
|
||||
$columnRow.removeClass(this.previewOpenClass);
|
||||
this.showExpandIcon($columnRow);
|
||||
this.hideCollapseIcon($columnRow);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.closeOpenedPreviews();
|
||||
|
||||
const dataUrl = $(event.currentTarget).data('preview-data-url');
|
||||
|
||||
if (this.isLocked(dataUrl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevents loading preview multiple times.
|
||||
// Uses "dataUrl" as lock key.
|
||||
this.lock(dataUrl);
|
||||
|
||||
$.ajax({
|
||||
url: dataUrl,
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
complete: () => {
|
||||
this.unlock(dataUrl);
|
||||
},
|
||||
}).then((response) => {
|
||||
this.renderPreviewContent($columnRow, response.preview);
|
||||
}).catch((e) => {
|
||||
window.showErrorMessage(e.responseJSON.message);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders preview content
|
||||
*
|
||||
* @param $columnRow
|
||||
* @param content
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
renderPreviewContent($columnRow, content) {
|
||||
const rowColumnCount = $columnRow.find('td').length;
|
||||
|
||||
const $previewTemplate = $(`
|
||||
<tr class="preview-row">
|
||||
<td colspan="${rowColumnCount}">${content}</td>
|
||||
</tr>
|
||||
`);
|
||||
|
||||
$columnRow.addClass(this.previewOpenClass);
|
||||
this.showCollapseIcon($columnRow);
|
||||
this.hideExpandIcon($columnRow);
|
||||
|
||||
if (typeof this.previewCustomization === 'function') {
|
||||
this.previewCustomization($previewTemplate);
|
||||
}
|
||||
|
||||
$columnRow.after($previewTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows preview expanding icon
|
||||
*
|
||||
* @param parent
|
||||
* @private
|
||||
*/
|
||||
showExpandIcon(parent) {
|
||||
parent.find(this.expandSelector).removeClass('d-none');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides preview expanding icon
|
||||
*
|
||||
* @param parent
|
||||
* @private
|
||||
*/
|
||||
hideExpandIcon(parent) {
|
||||
parent.find(this.expandSelector).addClass('d-none');
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows preview collapsing icon
|
||||
*
|
||||
* @param parent
|
||||
* @private
|
||||
*/
|
||||
showCollapseIcon(parent) {
|
||||
parent.find(this.collapseSelector).removeClass('d-none');
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides preview collapsing icon
|
||||
*
|
||||
* @param parent
|
||||
* @private
|
||||
*/
|
||||
hideCollapseIcon(parent) {
|
||||
parent.find(this.collapseSelector).addClass('d-none');
|
||||
}
|
||||
|
||||
isLocked(key) {
|
||||
return this.locks.indexOf(key) !== -1;
|
||||
}
|
||||
|
||||
lock(key) {
|
||||
if (this.isLocked(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.locks.push(key);
|
||||
}
|
||||
|
||||
unlock(key) {
|
||||
const index = this.locks.indexOf(key);
|
||||
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.locks.splice(index, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all previews that are open.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
closeOpenedPreviews() {
|
||||
const $rows = this.$gridContainer.find('.grid-table tbody').find('tr:not(.preview-row)');
|
||||
|
||||
$.each($rows, (i, row) => {
|
||||
const $row = $(row);
|
||||
|
||||
if (!$row.hasClass(this.previewOpenClass)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $previewRow = $row.next();
|
||||
|
||||
if (!$previewRow.hasClass('preview-row')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$previewRow.remove();
|
||||
$row.removeClass(this.previewOpenClass);
|
||||
this.hideCollapseIcon($row);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class ReloadListExtension extends grid with "List reload" action
|
||||
*/
|
||||
export default class ReloadListExtension {
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
grid.getHeaderContainer().on('click', '.js-common_refresh_list-grid-action', () => {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import TableSorting from '@app/utils/table-sorting';
|
||||
|
||||
/**
|
||||
* Class ReloadListExtension extends grid with "List reload" action
|
||||
*/
|
||||
export default class SortingExtension {
|
||||
/**
|
||||
* Extend grid
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
const $sortableTable = grid.getContainer().find('table.table');
|
||||
|
||||
new TableSorting($sortableTable).attach();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import ConfirmModal from '@components/modal';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Handles submit of grid actions
|
||||
*/
|
||||
export default class SubmitBulkActionExtension {
|
||||
constructor() {
|
||||
return {
|
||||
extend: (grid) => this.extend(grid),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend grid with bulk action submitting
|
||||
*
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
extend(grid) {
|
||||
grid.getContainer().on('click', '.js-bulk-action-submit-btn', (event) => {
|
||||
this.submit(event, grid);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle bulk action submitting
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Grid} grid
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
submit(event, grid) {
|
||||
const $submitBtn = $(event.currentTarget);
|
||||
const confirmMessage = $submitBtn.data('confirm-message');
|
||||
const confirmTitle = $submitBtn.data('confirmTitle');
|
||||
|
||||
if (confirmMessage !== undefined && confirmMessage.length > 0) {
|
||||
if (confirmTitle !== undefined) {
|
||||
this.showConfirmModal($submitBtn, grid, confirmMessage, confirmTitle);
|
||||
} else if (window.confirm(confirmMessage)) {
|
||||
this.postForm($submitBtn, grid);
|
||||
}
|
||||
} else {
|
||||
this.postForm($submitBtn, grid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {jQuery} $submitBtn
|
||||
* @param {Grid} grid
|
||||
* @param {string} confirmMessage
|
||||
* @param {string} confirmTitle
|
||||
*/
|
||||
showConfirmModal($submitBtn, grid, confirmMessage, confirmTitle) {
|
||||
const confirmButtonLabel = $submitBtn.data('confirmButtonLabel');
|
||||
const closeButtonLabel = $submitBtn.data('closeButtonLabel');
|
||||
const confirmButtonClass = $submitBtn.data('confirmButtonClass');
|
||||
|
||||
const modal = new ConfirmModal({
|
||||
id: `${grid.getId()}-grid-confirm-modal`,
|
||||
confirmTitle,
|
||||
confirmMessage,
|
||||
confirmButtonLabel,
|
||||
closeButtonLabel,
|
||||
confirmButtonClass,
|
||||
}, () => this.postForm($submitBtn, grid));
|
||||
|
||||
modal.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {jQuery} $submitBtn
|
||||
* @param {Grid} grid
|
||||
*/
|
||||
postForm($submitBtn, grid) {
|
||||
const $form = $(`#${grid.getId()}_filter_form`);
|
||||
|
||||
$form.attr('action', $submitBtn.data('form-url'));
|
||||
$form.attr('method', $submitBtn.data('form-method'));
|
||||
$form.submit();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class SubmitGridActionExtension handles grid action submits
|
||||
*/
|
||||
export default class SubmitGridActionExtension {
|
||||
constructor() {
|
||||
return {
|
||||
extend: (grid) => this.extend(grid),
|
||||
};
|
||||
}
|
||||
|
||||
extend(grid) {
|
||||
grid.getHeaderContainer().on('click', '.js-grid-action-submit-btn', (event) => {
|
||||
this.handleSubmit(event, grid);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle grid action submit.
|
||||
* It uses grid form to submit actions.
|
||||
*
|
||||
* @param {Event} event
|
||||
* @param {Grid} grid
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
handleSubmit(event, grid) {
|
||||
const $submitBtn = $(event.currentTarget);
|
||||
const confirmMessage = $submitBtn.data('confirm-message');
|
||||
|
||||
if (typeof confirmMessage !== 'undefined' && confirmMessage.length > 0 && !window.confirm(confirmMessage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $form = $(`#${grid.getId()}_filter_form`);
|
||||
|
||||
$form.attr('action', $submitBtn.data('url'));
|
||||
$form.attr('method', $submitBtn.data('method'));
|
||||
$form.find(`input[name="${grid.getId()}[_token]"]`).val($submitBtn.data('csrf'));
|
||||
$form.submit();
|
||||
}
|
||||
}
|
||||
77
admin-kalsport/themes/new-theme/js/components/grid/grid.js
Normal file
77
admin-kalsport/themes/new-theme/js/components/grid/grid.js
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class is responsible for handling Grid events
|
||||
*/
|
||||
export default class Grid {
|
||||
/**
|
||||
* Grid id
|
||||
*
|
||||
* @param {string} id
|
||||
*/
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
this.$container = $(`#${this.id}_grid`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get grid id
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get grid container
|
||||
*
|
||||
* @returns {jQuery}
|
||||
*/
|
||||
getContainer() {
|
||||
return this.$container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get grid header container
|
||||
*
|
||||
* @returns {jQuery}
|
||||
*/
|
||||
getHeaderContainer() {
|
||||
return this.$container.closest('.js-grid-panel').find('.js-grid-header');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend grid with external extensions
|
||||
*
|
||||
* @param {object} extension
|
||||
*/
|
||||
addExtension(extension) {
|
||||
extension.extend(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Takes link from clicked item and redirects to it.
|
||||
*/
|
||||
export default class LinkableItem {
|
||||
constructor() {
|
||||
$(document).on('click', '.js-linkable-item', (event) => {
|
||||
window.location = $(event.currentTarget).data('linkable-href');
|
||||
});
|
||||
}
|
||||
}
|
||||
163
admin-kalsport/themes/new-theme/js/components/modal.js
Normal file
163
admin-kalsport/themes/new-theme/js/components/modal.js
Normal file
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* ConfirmModal component
|
||||
*
|
||||
* @param {String} id
|
||||
* @param {String} confirmTitle
|
||||
* @param {String} confirmMessage
|
||||
* @param {String} closeButtonLabel
|
||||
* @param {String} confirmButtonLabel
|
||||
* @param {String} confirmButtonClass
|
||||
* @param {Array} customButtons
|
||||
* @param {Boolean} closable
|
||||
* @param {Function} confirmCallback
|
||||
* @param {Function} cancelCallback
|
||||
*
|
||||
*/
|
||||
export default function ConfirmModal(params, confirmCallback, cancelCallback) {
|
||||
// Construct the modal
|
||||
const {id, closable} = params;
|
||||
this.modal = Modal(params);
|
||||
|
||||
// jQuery modal object
|
||||
this.$modal = $(this.modal.container);
|
||||
|
||||
this.show = () => {
|
||||
this.$modal.modal();
|
||||
};
|
||||
|
||||
this.modal.confirmButton.addEventListener('click', confirmCallback);
|
||||
|
||||
this.$modal.modal({
|
||||
backdrop: closable ? true : 'static',
|
||||
keyboard: closable !== undefined ? closable : true,
|
||||
closable: closable !== undefined ? closable : true,
|
||||
show: false,
|
||||
});
|
||||
|
||||
this.$modal.on('hidden.bs.modal', () => {
|
||||
document.querySelector(`#${id}`).remove();
|
||||
if (cancelCallback) {
|
||||
cancelCallback();
|
||||
}
|
||||
});
|
||||
|
||||
document.body.appendChild(this.modal.container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal component to improve lisibility by constructing the modal outside the main function
|
||||
*
|
||||
* @param {Object} params
|
||||
*
|
||||
*/
|
||||
function Modal({
|
||||
id = 'confirm-modal',
|
||||
confirmTitle,
|
||||
confirmMessage = '',
|
||||
closeButtonLabel = 'Close',
|
||||
confirmButtonLabel = 'Accept',
|
||||
confirmButtonClass = 'btn-primary',
|
||||
customButtons = [],
|
||||
}) {
|
||||
const modal = {};
|
||||
|
||||
// Main modal element
|
||||
modal.container = document.createElement('div');
|
||||
modal.container.classList.add('modal', 'fade');
|
||||
modal.container.id = id;
|
||||
|
||||
// Modal dialog element
|
||||
modal.dialog = document.createElement('div');
|
||||
modal.dialog.classList.add('modal-dialog');
|
||||
|
||||
// Modal content element
|
||||
modal.content = document.createElement('div');
|
||||
modal.content.classList.add('modal-content');
|
||||
|
||||
// Modal header element
|
||||
modal.header = document.createElement('div');
|
||||
modal.header.classList.add('modal-header');
|
||||
|
||||
// Modal title element
|
||||
if (confirmTitle) {
|
||||
modal.title = document.createElement('h4');
|
||||
modal.title.classList.add('modal-title');
|
||||
modal.title.innerHTML = confirmTitle;
|
||||
}
|
||||
|
||||
// Modal close button icon
|
||||
modal.closeIcon = document.createElement('button');
|
||||
modal.closeIcon.classList.add('close');
|
||||
modal.closeIcon.setAttribute('type', 'button');
|
||||
modal.closeIcon.dataset.dismiss = 'modal';
|
||||
modal.closeIcon.innerHTML = '×';
|
||||
|
||||
// Modal body element
|
||||
modal.body = document.createElement('div');
|
||||
modal.body.classList.add('modal-body', 'text-left', 'font-weight-normal');
|
||||
|
||||
// Modal message element
|
||||
modal.message = document.createElement('p');
|
||||
modal.message.classList.add('confirm-message');
|
||||
modal.message.innerHTML = confirmMessage;
|
||||
|
||||
// Modal footer element
|
||||
modal.footer = document.createElement('div');
|
||||
modal.footer.classList.add('modal-footer');
|
||||
|
||||
// Modal close button element
|
||||
modal.closeButton = document.createElement('button');
|
||||
modal.closeButton.setAttribute('type', 'button');
|
||||
modal.closeButton.classList.add('btn', 'btn-outline-secondary', 'btn-lg');
|
||||
modal.closeButton.dataset.dismiss = 'modal';
|
||||
modal.closeButton.innerHTML = closeButtonLabel;
|
||||
|
||||
// Modal confirm button element
|
||||
modal.confirmButton = document.createElement('button');
|
||||
modal.confirmButton.setAttribute('type', 'button');
|
||||
modal.confirmButton.classList.add('btn', confirmButtonClass, 'btn-lg', 'btn-confirm-submit');
|
||||
modal.confirmButton.dataset.dismiss = 'modal';
|
||||
modal.confirmButton.innerHTML = confirmButtonLabel;
|
||||
|
||||
// Constructing the modal
|
||||
if (confirmTitle) {
|
||||
modal.header.append(modal.title, modal.closeIcon);
|
||||
} else {
|
||||
modal.header.appendChild(modal.closeIcon);
|
||||
}
|
||||
|
||||
modal.body.appendChild(modal.message);
|
||||
modal.footer.append(modal.closeButton, ...customButtons, modal.confirmButton);
|
||||
modal.content.append(modal.header, modal.body, modal.footer);
|
||||
modal.dialog.appendChild(modal.content);
|
||||
modal.container.appendChild(modal.dialog);
|
||||
|
||||
return modal;
|
||||
}
|
||||
431
admin-kalsport/themes/new-theme/js/components/module-card.js
Normal file
431
admin-kalsport/themes/new-theme/js/components/module-card.js
Normal file
@@ -0,0 +1,431 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
import ConfirmModal from '@components/modal';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
const BOEvent = {
|
||||
on(eventName, callback, context) {
|
||||
document.addEventListener(eventName, (event) => {
|
||||
if (typeof context !== 'undefined') {
|
||||
callback.call(context, event);
|
||||
} else {
|
||||
callback(event);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
emitEvent(eventName, eventType) {
|
||||
const event = document.createEvent(eventType);
|
||||
// true values stand for: can bubble, and is cancellable
|
||||
event.initEvent(eventName, true, true);
|
||||
document.dispatchEvent(event);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class is responsible for handling Module Card behavior
|
||||
*
|
||||
* This is a port of admin-dev/themes/default/js/bundle/module/module_card.js
|
||||
*/
|
||||
export default class ModuleCard {
|
||||
constructor() {
|
||||
/* 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';
|
||||
|
||||
this.initActionButtons();
|
||||
}
|
||||
|
||||
initActionButtons() {
|
||||
const self = this;
|
||||
|
||||
$(document).on('click', this.forceDeletionOption, function () {
|
||||
const btn = $(
|
||||
self.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 (
|
||||
self.dispatchPreEvent('install', this)
|
||||
&& self.confirmAction('install', this)
|
||||
&& self.requestToController('install', $(this))
|
||||
);
|
||||
});
|
||||
|
||||
$(document).on('click', this.moduleActionMenuEnableLinkSelector, function () {
|
||||
return (
|
||||
self.dispatchPreEvent('enable', this)
|
||||
&& self.confirmAction('enable', this)
|
||||
&& self.requestToController('enable', $(this))
|
||||
);
|
||||
});
|
||||
|
||||
$(document).on('click', this.moduleActionMenuUninstallLinkSelector, function () {
|
||||
return (
|
||||
self.dispatchPreEvent('uninstall', this)
|
||||
&& self.confirmAction('uninstall', this)
|
||||
&& self.requestToController('uninstall', $(this))
|
||||
);
|
||||
});
|
||||
|
||||
$(document).on('click', this.moduleActionMenuDisableLinkSelector, function () {
|
||||
return (
|
||||
self.dispatchPreEvent('disable', this)
|
||||
&& self.confirmAction('disable', this)
|
||||
&& self.requestToController('disable', $(this))
|
||||
);
|
||||
});
|
||||
|
||||
$(document).on('click', this.moduleActionMenuEnableMobileLinkSelector, function () {
|
||||
return (
|
||||
self.dispatchPreEvent('enable_mobile', this)
|
||||
&& self.confirmAction('enable_mobile', this)
|
||||
&& self.requestToController('enable_mobile', $(this))
|
||||
);
|
||||
});
|
||||
|
||||
$(document).on('click', this.moduleActionMenuDisableMobileLinkSelector, function () {
|
||||
return (
|
||||
self.dispatchPreEvent('disable_mobile', this)
|
||||
&& self.confirmAction('disable_mobile', this)
|
||||
&& self.requestToController('disable_mobile', $(this))
|
||||
);
|
||||
});
|
||||
|
||||
$(document).on('click', this.moduleActionMenuResetLinkSelector, function () {
|
||||
return (
|
||||
self.dispatchPreEvent('reset', this)
|
||||
&& self.confirmAction('reset', this)
|
||||
&& self.requestToController('reset', $(this))
|
||||
);
|
||||
});
|
||||
|
||||
$(document).on('click', this.moduleActionMenuUpdateLinkSelector, function (event) {
|
||||
event.preventDefault();
|
||||
const modal = $(`#${$(this).data('confirm_modal')}`);
|
||||
const isMaintenanceMode = window.isShopMaintenance;
|
||||
|
||||
if (modal.length !== 1) {
|
||||
// Modal body element
|
||||
const maintenanceLink = document.createElement('a');
|
||||
maintenanceLink.classList.add('btn', 'btn-primary', 'btn-lg');
|
||||
maintenanceLink.setAttribute('href', window.moduleURLs.maintenancePage);
|
||||
maintenanceLink.innerHTML = window.moduleTranslations.moduleModalUpdateMaintenance;
|
||||
|
||||
const updateConfirmModal = new ConfirmModal(
|
||||
{
|
||||
id: 'confirm-module-update-modal',
|
||||
confirmTitle: window.moduleTranslations.singleModuleModalUpdateTitle,
|
||||
closeButtonLabel: window.moduleTranslations.moduleModalUpdateCancel,
|
||||
confirmButtonLabel: isMaintenanceMode
|
||||
? window.moduleTranslations.moduleModalUpdateUpgrade
|
||||
: window.moduleTranslations.upgradeAnywayButtonText,
|
||||
confirmButtonClass: isMaintenanceMode ? 'btn-primary' : 'btn-secondary',
|
||||
confirmMessage: isMaintenanceMode ? '' : window.moduleTranslations.moduleModalUpdateConfirmMessage,
|
||||
closable: true,
|
||||
customButtons: isMaintenanceMode ? [] : [maintenanceLink],
|
||||
},
|
||||
|
||||
() => self.dispatchPreEvent('update', this)
|
||||
&& self.confirmAction('update', this)
|
||||
&& self.requestToController('update', $(this)),
|
||||
);
|
||||
|
||||
updateConfirmModal.show();
|
||||
} else {
|
||||
return (
|
||||
self.dispatchPreEvent('update', this)
|
||||
&& self.confirmAction('update', this)
|
||||
&& self.requestToController('update', $(this))
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).on('click', this.moduleActionModalDisableLinkSelector, function () {
|
||||
return self.requestToController(
|
||||
'disable',
|
||||
$(
|
||||
self.moduleActionMenuDisableLinkSelector,
|
||||
$(`div.module-item-list[data-tech-name='${$(this).attr('data-tech-name')}']`),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
$(document).on('click', this.moduleActionModalResetLinkSelector, function () {
|
||||
return self.requestToController(
|
||||
'reset',
|
||||
$(
|
||||
self.moduleActionMenuResetLinkSelector,
|
||||
$(`div.module-item-list[data-tech-name='${$(this).attr('data-tech-name')}']`),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
$(document).on('click', this.moduleActionModalUninstallLinkSelector, (e) => {
|
||||
$(e.target)
|
||||
.parents('.modal')
|
||||
.on('hidden.bs.modal', () => self.requestToController(
|
||||
'uninstall',
|
||||
$(
|
||||
self.moduleActionMenuUninstallLinkSelector,
|
||||
$(`div.module-item-list[data-tech-name='${$(e.target).attr('data-tech-name')}']`),
|
||||
),
|
||||
$(e.target).attr('data-deletion'),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getModuleItemSelector() {
|
||||
if ($(this.moduleItemListSelector).length) {
|
||||
return this.moduleItemListSelector;
|
||||
}
|
||||
|
||||
return this.moduleItemGridSelector;
|
||||
}
|
||||
|
||||
confirmAction(action, element) {
|
||||
const 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}
|
||||
*/
|
||||
confirmPrestaTrust(result) {
|
||||
const that = this;
|
||||
const modal = this.replacePrestaTrustPlaceholders(result);
|
||||
|
||||
modal
|
||||
.find('.pstrust-install')
|
||||
.off('click')
|
||||
.on('click', () => {
|
||||
// Find related form, update it and submit it
|
||||
const installButton = $(
|
||||
that.moduleActionMenuInstallLinkSelector,
|
||||
`.module-item[data-tech-name="${result.module.attributes.name}"]`,
|
||||
);
|
||||
|
||||
const form = installButton.parent('form');
|
||||
$('<input>')
|
||||
.attr({
|
||||
type: 'hidden',
|
||||
value: '1',
|
||||
name: 'actionParams[confirmPrestaTrust]',
|
||||
})
|
||||
.appendTo(form);
|
||||
|
||||
installButton.click();
|
||||
modal.modal('hide');
|
||||
});
|
||||
|
||||
modal.modal();
|
||||
}
|
||||
|
||||
replacePrestaTrustPlaceholders(result) {
|
||||
const modal = $('#modal-prestatrust');
|
||||
const module = result.module.attributes;
|
||||
|
||||
if (result.confirmation_subject !== 'PrestaTrust' || !modal.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const 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;
|
||||
}
|
||||
|
||||
dispatchPreEvent(action, element) {
|
||||
const 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.
|
||||
}
|
||||
|
||||
requestToController(action, element, forceDeletion, disableCacheClear, callback) {
|
||||
const self = this;
|
||||
const jqElementObj = element.closest(this.moduleItemActionsSelector);
|
||||
const form = element.closest('form');
|
||||
const spinnerObj = $('<button class="btn-primary-reverse onclick unbind spinner "></button>');
|
||||
const url = `//${window.location.host}${form.attr('action')}`;
|
||||
const actionParams = form.serializeArray();
|
||||
|
||||
if (forceDeletion === 'true' || forceDeletion === true) {
|
||||
actionParams.push({name: 'actionParams[deletion]', value: true});
|
||||
}
|
||||
if (disableCacheClear === 'true' || disableCacheClear === true) {
|
||||
actionParams.push({name: 'actionParams[cacheClearEnabled]', value: 0});
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url,
|
||||
dataType: 'json',
|
||||
method: 'POST',
|
||||
data: actionParams,
|
||||
beforeSend() {
|
||||
jqElementObj.hide();
|
||||
jqElementObj.after(spinnerObj);
|
||||
},
|
||||
})
|
||||
.done((result) => {
|
||||
if (result === undefined) {
|
||||
$.growl.error({
|
||||
message: 'No answer received from server',
|
||||
fixed: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof result.status !== 'undefined' && result.status === false) {
|
||||
$.growl.error({message: result.msg, fixed: true});
|
||||
return;
|
||||
}
|
||||
|
||||
const moduleTechName = Object.keys(result)[0];
|
||||
|
||||
if (result[moduleTechName].status === false) {
|
||||
if (typeof result[moduleTechName].confirmation_subject !== 'undefined') {
|
||||
self.confirmPrestaTrust(result[moduleTechName]);
|
||||
}
|
||||
|
||||
$.growl.error({message: result[moduleTechName].msg, fixed: true});
|
||||
return;
|
||||
}
|
||||
|
||||
$.growl({
|
||||
message: result[moduleTechName].msg,
|
||||
duration: 6000,
|
||||
});
|
||||
|
||||
const alteredSelector = self.getModuleItemSelector().replace('.', '');
|
||||
let mainElement = null;
|
||||
|
||||
if (action === 'uninstall') {
|
||||
mainElement = jqElementObj.closest(`.${alteredSelector}`);
|
||||
mainElement.remove();
|
||||
|
||||
BOEvent.emitEvent('Module Uninstalled', 'CustomEvent');
|
||||
} else if (action === 'disable') {
|
||||
mainElement = jqElementObj.closest(`.${alteredSelector}`);
|
||||
mainElement.addClass(`${alteredSelector}-isNotActive`);
|
||||
mainElement.attr('data-active', '0');
|
||||
|
||||
BOEvent.emitEvent('Module Disabled', 'CustomEvent');
|
||||
} else if (action === 'enable') {
|
||||
mainElement = jqElementObj.closest(`.${alteredSelector}`);
|
||||
mainElement.removeClass(`${alteredSelector}-isNotActive`);
|
||||
mainElement.attr('data-active', '1');
|
||||
|
||||
BOEvent.emitEvent('Module Enabled', 'CustomEvent');
|
||||
}
|
||||
|
||||
jqElementObj.replaceWith(result[moduleTechName].action_menu_html);
|
||||
})
|
||||
.fail(() => {
|
||||
const moduleItem = jqElementObj.closest('module-item-list');
|
||||
const techName = moduleItem.data('techName');
|
||||
$.growl.error({
|
||||
message: `Could not perform action ${action} for module ${techName}`,
|
||||
fixed: true,
|
||||
});
|
||||
})
|
||||
.always(() => {
|
||||
jqElementObj.fadeIn();
|
||||
spinnerObj.remove();
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encapsulates selectors for multi store restriction component
|
||||
*/
|
||||
export default {
|
||||
multiStoreRestrictionCheckbox: '.js-multi-store-restriction-checkbox',
|
||||
multiStoreRestrictionSwitch: '.js-multi-store-restriction-switch',
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import multiStoreRestrictionFieldMap from './multi-store-restriction-field-map';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Enables multi store functionality for the page. It includes switch functionality and checkboxes
|
||||
*/
|
||||
export default class MultiStoreRestrictionField {
|
||||
constructor() {
|
||||
$(document).on(
|
||||
'change',
|
||||
multiStoreRestrictionFieldMap.multiStoreRestrictionCheckbox,
|
||||
(e) => this.multiStoreRestrictionCheckboxFieldChangeEvent(e),
|
||||
);
|
||||
|
||||
$(document).on(
|
||||
'change',
|
||||
multiStoreRestrictionFieldMap.multiStoreRestrictionSwitch,
|
||||
(e) => this.multiStoreRestrictionSwitchFieldChangeEvent(e),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the checkbox field and enables or disables its related field.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @private
|
||||
*/
|
||||
multiStoreRestrictionCheckboxFieldChangeEvent(e) {
|
||||
const $currentItem = $(e.currentTarget);
|
||||
|
||||
this.toggleSourceFieldByTargetElement($currentItem, !$currentItem.is(':checked'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass updates multi-store checkbox fields - it enables or disabled the switch and after that
|
||||
* it calls the function
|
||||
* which handles the toggle update related form field by its current state.
|
||||
* @param {Event} e
|
||||
* @private
|
||||
*/
|
||||
multiStoreRestrictionSwitchFieldChangeEvent(e) {
|
||||
const $currentItem = $(e.currentTarget);
|
||||
const isSelected = parseInt($currentItem.val(), 10) === 1;
|
||||
const targetFormName = $currentItem.data('targetFormName');
|
||||
|
||||
$(`form[name="${targetFormName}"]`)
|
||||
.find(multiStoreRestrictionFieldMap.multiStoreRestrictionCheckbox)
|
||||
.each((index, el) => {
|
||||
const $el = $(el);
|
||||
$el.prop('checked', isSelected);
|
||||
this.toggleSourceFieldByTargetElement($el, !isSelected);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes related form fields state to disabled or enabled.
|
||||
* It also toggles class disabled since for some fields
|
||||
* this class is used instead of the native disabled attribute.
|
||||
*
|
||||
* @param {jquery} $targetElement
|
||||
* @param {boolean} isDisabled
|
||||
* @private
|
||||
*/
|
||||
toggleSourceFieldByTargetElement($targetElement, isDisabled) {
|
||||
const targetValue = $targetElement.data('shopRestrictionTarget');
|
||||
const $sourceFieldSelector = $(`[data-shop-restriction-source="${targetValue}"]`);
|
||||
$sourceFieldSelector.prop('disabled', isDisabled);
|
||||
$sourceFieldSelector.toggleClass('disabled', isDisabled);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* MultipleChoiceTable is responsible for managing common actions in multiple choice table form type
|
||||
*/
|
||||
export default class MultipleChoiceTable {
|
||||
/**
|
||||
* Init constructor
|
||||
*/
|
||||
constructor() {
|
||||
$(document).on('click', '.js-multiple-choice-table-select-column', (e) => this.handleSelectColumn(e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check/uncheck all boxes in column
|
||||
*
|
||||
* @param {Event} event
|
||||
*/
|
||||
handleSelectColumn(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const $selectColumnBtn = $(event.target);
|
||||
const checked = $selectColumnBtn.data('column-checked');
|
||||
$selectColumnBtn.data('column-checked', !checked);
|
||||
|
||||
const $table = $selectColumnBtn.closest('table');
|
||||
|
||||
$table
|
||||
.find(`tbody tr td:nth-child(${$selectColumnBtn.data('column-num')}) input[type=checkbox]`)
|
||||
.prop('checked', !checked);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import Bloodhound from 'typeahead.js';
|
||||
import Router from '@components/router';
|
||||
import AutoCompleteSearch from '@components/auto-complete-search';
|
||||
import PerfectScrollbar from 'perfect-scrollbar';
|
||||
import ComponentsMap from '@components/components-map';
|
||||
import 'perfect-scrollbar/css/perfect-scrollbar.css';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
const initMultistoreDropdown = () => {
|
||||
const MultistoreDropdownMap = ComponentsMap.multistoreDropdown;
|
||||
const $searchInput = $(MultistoreDropdownMap.searchInput);
|
||||
const router = new Router();
|
||||
const route = router.generate('admin_shops_search', {
|
||||
searchTerm: '__QUERY__',
|
||||
});
|
||||
|
||||
if ($(MultistoreDropdownMap.scrollbar).length > 0) {
|
||||
new PerfectScrollbar(MultistoreDropdownMap.scrollbar);
|
||||
}
|
||||
|
||||
const source = new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace,
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
remote: {
|
||||
url: route,
|
||||
wildcard: '__QUERY__',
|
||||
},
|
||||
});
|
||||
|
||||
const dataSetConfig = {
|
||||
display: 'name',
|
||||
value: 'id',
|
||||
source,
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
onSelect(selectedItem, event) {
|
||||
const contextUrlLetter = typeof selectedItem.groupName !== 'undefined' ? 's' : 'g';
|
||||
window.location.href = ComponentsMap.multistoreHeader.setContextUrl(
|
||||
window.location.href,
|
||||
contextUrlLetter,
|
||||
selectedItem.id,
|
||||
);
|
||||
|
||||
return true;
|
||||
},
|
||||
/* eslint-disable-next-line no-unused-vars */
|
||||
onClose(event) {},
|
||||
};
|
||||
|
||||
new AutoCompleteSearch($searchInput, dataSetConfig);
|
||||
};
|
||||
|
||||
$(() => {
|
||||
initMultistoreDropdown();
|
||||
});
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import Bloodhound from 'typeahead.js';
|
||||
import Router from '@components/router';
|
||||
import AutoCompleteSearch from '@components/auto-complete-search';
|
||||
import PerfectScrollbar from 'perfect-scrollbar';
|
||||
import ComponentsMap from '@components/components-map';
|
||||
import 'perfect-scrollbar/css/perfect-scrollbar.css';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
const initMultistoreHeader = () => {
|
||||
const MultistoreHeaderMap = ComponentsMap.multistoreHeader;
|
||||
const headerButton = document.querySelector(MultistoreHeaderMap.headerButton);
|
||||
const modalMultishop = document.querySelector(MultistoreHeaderMap.modal);
|
||||
const $searchInput = $(MultistoreHeaderMap.searchInput);
|
||||
const router = new Router();
|
||||
const route = router.generate('admin_shops_search', {
|
||||
searchTerm: '__QUERY__',
|
||||
});
|
||||
|
||||
new PerfectScrollbar(MultistoreHeaderMap.jsScrollbar);
|
||||
|
||||
const source = new Bloodhound({
|
||||
datumTokenizer: Bloodhound.tokenizers.obj.whitespace,
|
||||
queryTokenizer: Bloodhound.tokenizers.whitespace,
|
||||
remote: {
|
||||
url: route,
|
||||
wildcard: '__QUERY__',
|
||||
},
|
||||
});
|
||||
|
||||
const dataSetConfig = {
|
||||
source,
|
||||
onSelect(selectedItem) {
|
||||
const contextUrlLetter = typeof selectedItem.groupName !== 'undefined' ? 's' : 'g';
|
||||
const setContextUrl = MultistoreHeaderMap.setContextUrl(window.location.href, contextUrlLetter, selectedItem.id);
|
||||
window.location.href = setContextUrl;
|
||||
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
new AutoCompleteSearch($searchInput, dataSetConfig);
|
||||
|
||||
headerButton.addEventListener('click', () => {
|
||||
modalMultishop.classList.toggle('multishop-modal-hidden');
|
||||
headerButton.classList.toggle('active');
|
||||
});
|
||||
};
|
||||
|
||||
$(() => {
|
||||
initMultistoreHeader();
|
||||
});
|
||||
111
admin-kalsport/themes/new-theme/js/components/navbar-handler.js
Normal file
111
admin-kalsport/themes/new-theme/js/components/navbar-handler.js
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
/**
|
||||
* This component watches a navigation bar and is able to link it alternative links, and automatic switch
|
||||
* on page load.
|
||||
*
|
||||
* You can add button with class tab-link when they are clicked the tab target is fetched
|
||||
* from the button's data property targetTab (so data-target-tab), it then search for a tab
|
||||
* which targets matches in the navbar and simulates a click on it.
|
||||
*
|
||||
* Alternatively it also checks on page load if a hash matches a tab and activates it if one is found,
|
||||
* and of course the hash is kept in sync when the navbar or alternative links are used.
|
||||
*/
|
||||
export default class NavbarHandler {
|
||||
constructor($navigationContainer, tabPrefix) {
|
||||
// We use a tab prefix for hastag so that on reload the page doesn't auto scroll to the anchored element
|
||||
this.tabPrefix = tabPrefix || 'tab-';
|
||||
this.$navigationContainer = $navigationContainer;
|
||||
|
||||
this.watchNavbar();
|
||||
this.watchTabLinks();
|
||||
this.switchOnPageLoad();
|
||||
}
|
||||
|
||||
switchToTarget(target) {
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
const matchingTabs = $(`[href="${target}"]`, this.$navigationContainer);
|
||||
|
||||
if (matchingTabs.length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tabLink = matchingTabs.first();
|
||||
this.switchToTab(tabLink);
|
||||
}
|
||||
|
||||
switchToTab(tab) {
|
||||
tab.click();
|
||||
this.updateBrowserHash(tab.attr('href'));
|
||||
}
|
||||
|
||||
updateBrowserHash(target) {
|
||||
const hashName = target.replace('#', `#${this.tabPrefix}`);
|
||||
|
||||
if (window.history.pushState) {
|
||||
window.history.pushState(null, null, hashName);
|
||||
} else {
|
||||
window.location.hash = hashName;
|
||||
}
|
||||
}
|
||||
|
||||
watchNavbar() {
|
||||
$(this.$navigationContainer).on('shown.bs.tab', (event) => {
|
||||
if (event.target.hash) {
|
||||
this.updateBrowserHash(event.target.hash);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
watchTabLinks() {
|
||||
$('.tab-link').click((event) => {
|
||||
event.preventDefault();
|
||||
const target = $(event.target).attr('href');
|
||||
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.switchToTarget(`${target}`);
|
||||
});
|
||||
}
|
||||
|
||||
switchOnPageLoad() {
|
||||
const errorTabs = $('.has-error', this.$navigationContainer);
|
||||
|
||||
if (errorTabs.length) {
|
||||
const errorTab = $('a[role="tab"]', errorTabs.first()).first();
|
||||
this.switchToTab(errorTab);
|
||||
} else {
|
||||
const {hash} = document.location;
|
||||
const target = hash.replace(`#${this.tabPrefix}`, '#');
|
||||
this.switchToTarget(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Toggle a class on $mainMenu after the end of an event (transition, animation...)
|
||||
* @param {jQuery element} $navBar - The navbar item which get a css transition property.
|
||||
* @param {jQuery element} $mainMenu - The menu inside the $navBar element.
|
||||
* @param {string} endTransitionEvent - The name of the event.
|
||||
* @param {jQuery element} $body - The body of the page.
|
||||
* @method showNavBarContent - Toggle the class based on event and if body got a class.
|
||||
* @method toggle - Add the listener if there is no transition launched yet.
|
||||
* @return {Object} The object with methods wich permit to toggle on specific event.
|
||||
*/
|
||||
function NavbarTransitionHandler($navBar, $mainMenu, endTransitionEvent, $body) {
|
||||
this.$body = $body;
|
||||
this.transitionFired = false;
|
||||
this.$navBar = $navBar.get(0);
|
||||
this.$mainMenu = $mainMenu;
|
||||
this.endTransitionEvent = endTransitionEvent;
|
||||
|
||||
this.showNavBarContent = (event) => {
|
||||
if (event.propertyName !== 'width') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$navBar.removeEventListener(this.endTransitionEvent, this.showNavBarContent);
|
||||
const isSidebarClosed = this.$body.hasClass('page-sidebar-closed');
|
||||
this.$mainMenu.toggleClass('sidebar-closed', isSidebarClosed);
|
||||
this.transitionFired = false;
|
||||
};
|
||||
|
||||
this.toggle = () => {
|
||||
if (!this.transitionFired) {
|
||||
this.$navBar.addEventListener(this.endTransitionEvent, this.showNavBarContent.bind(this));
|
||||
} else {
|
||||
this.$navBar.removeEventListener(this.endTransitionEvent, this.showNavBarContent);
|
||||
}
|
||||
|
||||
this.transitionFired = !this.transitionFired;
|
||||
};
|
||||
}
|
||||
|
||||
export default NavbarTransitionHandler;
|
||||
@@ -0,0 +1,266 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Related html template src/PrestaShopBundle/Resources/views/Admin/Common/javascript_pagination.html.twig
|
||||
*
|
||||
* Usage
|
||||
*```
|
||||
* $paginator new DynamicPaginator(
|
||||
* '#foo-container',
|
||||
* FooDataService,
|
||||
* FooRenderer
|
||||
* );
|
||||
* this.eventEmitter.on('fooEventThatShouldTriggerPagination', () => $paginator.paginate(1));
|
||||
*```
|
||||
* You can also provide the starting page to initiate it automatically on page load:
|
||||
*```
|
||||
* $paginator new DynamicPaginator(
|
||||
* '#foo-container',
|
||||
* FooDataService,
|
||||
* FooRenderer,
|
||||
* 1
|
||||
* );
|
||||
*```
|
||||
* There is also a possibility to provide custom selectorsMap as 5th argument. See this.setSelectorsMap().
|
||||
*
|
||||
* Pagination service must have a method fetch(offset, limit) which returns data.{any resources name} & data.total
|
||||
* e.g.
|
||||
* ```
|
||||
* class FooDataService {
|
||||
* fetch(offset, limit) {
|
||||
* return $.get(this.router.generate('admin_products_combinations', {
|
||||
* productId: this.productId,
|
||||
* page,
|
||||
* limit,
|
||||
* }));
|
||||
* }
|
||||
* }
|
||||
*```
|
||||
* * In this case the action of route `admin_products_combinations` returns following json:
|
||||
* ```
|
||||
* {
|
||||
* total: 100,
|
||||
* combinations: [{combinationId: 1, name: foo...}, {combinationId: 2, name: bar...}]
|
||||
* }
|
||||
*```
|
||||
*
|
||||
* The renderer must have a method render(data) which accepts the data from PaginationService
|
||||
* and renders it depending on needs
|
||||
*/
|
||||
export default class DynamicPaginator {
|
||||
/**
|
||||
* @param {String} containerSelector
|
||||
* @param {Object} paginationService
|
||||
* @param {Object} renderer
|
||||
* @param {Number|null} startingPage If provided it will load the provided page data on page load
|
||||
* @param {Object|null} selectorsMap If provided it will override css selectors used for all the actions.
|
||||
*/
|
||||
constructor(containerSelector, paginationService, renderer, startingPage = null, selectorsMap = null) {
|
||||
this.$paginationContainer = $(containerSelector);
|
||||
this.paginationService = paginationService;
|
||||
this.renderer = renderer;
|
||||
this.setSelectorsMap(selectorsMap);
|
||||
this.init();
|
||||
this.currentPage = 1;
|
||||
if (startingPage !== null) {
|
||||
this.paginate(startingPage);
|
||||
}
|
||||
|
||||
return {
|
||||
paginate: (page) => this.paginate(page),
|
||||
getCurrentPage: () => this.currentPage,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the pagination component
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
init() {
|
||||
this.$paginationContainer.on('click', this.selectorsMap.pageLink, (e) => {
|
||||
this.paginate(Number($(e.currentTarget).data('page')));
|
||||
});
|
||||
this.$paginationContainer.find(this.selectorsMap.jumpToPageInput).keypress((e) => {
|
||||
if (e.which === 13) {
|
||||
e.preventDefault();
|
||||
const page = this.getValidPageNumber(Number(e.currentTarget.value));
|
||||
this.paginate(page);
|
||||
}
|
||||
});
|
||||
this.$paginationContainer.on('change', this.selectorsMap.limitSelect, () => {
|
||||
this.paginate(1);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} page
|
||||
*/
|
||||
async paginate(page) {
|
||||
this.currentPage = page;
|
||||
this.renderer.toggleLoading(true);
|
||||
const limit = this.getLimit();
|
||||
const data = await this.paginationService.fetch(this.calculateOffset(page, limit), limit);
|
||||
$(this.selectorsMap.jumpToPageInput).val(page);
|
||||
this.countPages(data.total);
|
||||
this.refreshButtonsData(page);
|
||||
this.refreshInfoLabel(page, data.total);
|
||||
|
||||
this.toggleTargetAvailability(this.selectorsMap.firstPageItem, page > 1);
|
||||
this.toggleTargetAvailability(this.selectorsMap.previousPageItem, page > 1);
|
||||
this.toggleTargetAvailability(this.selectorsMap.nextPageItem, page < this.pagesCount);
|
||||
this.toggleTargetAvailability(this.selectorsMap.lastPageItem, page < this.pagesCount);
|
||||
|
||||
this.renderer.render(data);
|
||||
this.renderer.toggleLoading(false);
|
||||
|
||||
window.prestaShopUiKit.initToolTips();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param page
|
||||
* @param limit
|
||||
*
|
||||
* @returns {Number}
|
||||
*/
|
||||
calculateOffset(page, limit) {
|
||||
return (page - 1) * limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} page
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
refreshButtonsData(page) {
|
||||
this.$paginationContainer.find(this.selectorsMap.nextPageBtn).data('page', page + 1);
|
||||
this.$paginationContainer.find(this.selectorsMap.previousPageBtn).data('page', page - 1);
|
||||
this.$paginationContainer.find(this.selectorsMap.lastPageBtn).data('page', this.pagesCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} page
|
||||
* @param {Number} total
|
||||
*/
|
||||
refreshInfoLabel(page, total) {
|
||||
const infoLabel = this.$paginationContainer.find(this.selectorsMap.paginationInfoLabel);
|
||||
const limit = this.getLimit();
|
||||
const from = page === 1 ? 1 : Math.round((page - 1) * limit);
|
||||
const to = page === this.pagesCount ? total : Math.round(page * limit);
|
||||
const modifiedInfoText = infoLabel
|
||||
.data('pagination-info')
|
||||
.replace(/%from%/g, from)
|
||||
.replace(/%to%/g, to)
|
||||
.replace(/%total%/g, total)
|
||||
.replace(/%current_page%/g, page)
|
||||
.replace(/%page_count%/g, this.pagesCount);
|
||||
|
||||
infoLabel.text(modifiedInfoText);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} targetSelector
|
||||
* @param {Boolean} enable
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggleTargetAvailability(targetSelector, enable) {
|
||||
const target = this.$paginationContainer.find(targetSelector);
|
||||
|
||||
if (enable) {
|
||||
target.removeClass('disabled');
|
||||
} else {
|
||||
target.addClass('disabled');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} total
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
countPages(total) {
|
||||
this.pagesCount = Math.ceil(total / this.getLimit());
|
||||
const lastPageItem = this.$paginationContainer.find(this.selectorsMap.lastPageBtn);
|
||||
lastPageItem.data('page', this.pagesCount);
|
||||
lastPageItem.text(this.pagesCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Number}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
getLimit() {
|
||||
return this.$paginationContainer.find(this.selectorsMap.limitSelect).val();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param page
|
||||
*
|
||||
* @returns {Number}
|
||||
*/
|
||||
getValidPageNumber(page) {
|
||||
if (page > this.pagesCount) {
|
||||
return this.pagesCount;
|
||||
}
|
||||
|
||||
if (page < 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} selectorsMap
|
||||
*/
|
||||
setSelectorsMap(selectorsMap) {
|
||||
if (selectorsMap) {
|
||||
this.selectorsMap = selectorsMap;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectorsMap = {
|
||||
jumpToPageInput: 'input[name="paginator-jump-page"]',
|
||||
firstPageBtn: 'button.page-link.first',
|
||||
firstPageItem: 'li.page-item.first',
|
||||
nextPageBtn: 'button.page-link.next',
|
||||
nextPageItem: 'li.page-item.next',
|
||||
previousPageBtn: 'button.page-link.previous',
|
||||
previousPageItem: 'li.page-item.previous',
|
||||
lastPageItem: 'li.page-item.last',
|
||||
lastPageBtn: 'button.page-link.last',
|
||||
pageLink: 'button.page-link',
|
||||
limitSelect: '#paginator-limit',
|
||||
paginationInfoLabel: '#pagination-info',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class responsible for checking password's validity.
|
||||
* Can validate entered password's length against min/max values.
|
||||
* If password confirmation input is provided, can validate if entered password is matching confirmation.
|
||||
*/
|
||||
export default class PasswordValidator {
|
||||
/**
|
||||
* @param {String} passwordInputSelector selector of the password input.
|
||||
* @param {String|null} confirmPasswordInputSelector (optional) selector for the password confirmation input.
|
||||
* @param {Object} options allows overriding default options.
|
||||
*/
|
||||
constructor(passwordInputSelector, confirmPasswordInputSelector = null, options = {}) {
|
||||
this.newPasswordInput = document.querySelector(passwordInputSelector);
|
||||
this.confirmPasswordInput = document.querySelector(confirmPasswordInputSelector);
|
||||
|
||||
// Minimum allowed length for entered password
|
||||
this.minPasswordLength = options.minPasswordLength || 8;
|
||||
|
||||
// Maximum allowed length for entered password
|
||||
this.maxPasswordLength = options.maxPasswordLength || 255;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the password is valid.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isPasswordValid() {
|
||||
if (this.confirmPasswordInput && !this.isPasswordMatchingConfirmation()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.isPasswordLengthValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if password's length is valid.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isPasswordLengthValid() {
|
||||
return !this.isPasswordTooShort() && !this.isPasswordTooLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if password is matching it's confirmation.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isPasswordMatchingConfirmation() {
|
||||
if (!this.confirmPasswordInput) {
|
||||
throw new Error('Confirm password input is not provided for the password validator.');
|
||||
}
|
||||
|
||||
if (this.confirmPasswordInput.value === '') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.newPasswordInput.value === this.confirmPasswordInput.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if password is too short.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isPasswordTooShort() {
|
||||
return this.newPasswordInput.value.length < this.minPasswordLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if password is too long.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isPasswordTooLong() {
|
||||
return this.newPasswordInput.value.length > this.maxPasswordLength;
|
||||
}
|
||||
}
|
||||
77
admin-kalsport/themes/new-theme/js/components/router.js
Normal file
77
admin-kalsport/themes/new-theme/js/components/router.js
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import Routing from 'fos-routing';
|
||||
import routes from '@js/fos_js_routes.json';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Wraps FOSJsRoutingbundle with exposed routes.
|
||||
* To expose route add option `expose: true` in .yml routing config
|
||||
*
|
||||
* e.g.
|
||||
*
|
||||
* `my_route
|
||||
* path: /my-path
|
||||
* options:
|
||||
* expose: true
|
||||
* `
|
||||
* And run `bin/console fos:js-routing:dump --format=json --target=admin-dev/themes/new-theme/js/fos_js_routes.json`
|
||||
*/
|
||||
export default class Router {
|
||||
constructor() {
|
||||
if (window.prestashop && window.prestashop.customRoutes) {
|
||||
Object.assign(routes.routes, window.prestashop.customRoutes);
|
||||
}
|
||||
|
||||
Routing.setData(routes);
|
||||
Routing.setBaseUrl(
|
||||
$(document)
|
||||
.find('body')
|
||||
.data('base-url'),
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorated "generate" method, with predefined security token in params
|
||||
*
|
||||
* @param route
|
||||
* @param params
|
||||
*
|
||||
* @returns {String}
|
||||
*/
|
||||
generate(route, params = {}) {
|
||||
const tokenizedParams = Object.assign(params, {
|
||||
_token: $(document)
|
||||
.find('body')
|
||||
.data('token'),
|
||||
});
|
||||
|
||||
return Routing.generate(route, tokenizedParams);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class ShowcaseCardCloseExtension is responsible for providing helper block closing behavior
|
||||
*/
|
||||
export default class ShowcaseCardCloseExtension {
|
||||
/**
|
||||
* Extend helper block.
|
||||
*
|
||||
* @param {ShowcaseCard} helperBlock
|
||||
*/
|
||||
extend(helperBlock) {
|
||||
const container = helperBlock.getContainer();
|
||||
container.on('click', '.js-remove-helper-block', (evt) => {
|
||||
container.remove();
|
||||
|
||||
const $btn = $(evt.target);
|
||||
const url = $btn.data('closeUrl');
|
||||
const cardName = $btn.data('cardName');
|
||||
|
||||
if (url) {
|
||||
// notify the card was closed
|
||||
$.post(
|
||||
url,
|
||||
{
|
||||
close: 1,
|
||||
name: cardName,
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Class ShowcaseCard is responsible for handling events related with showcase card.
|
||||
*/
|
||||
export default class ShowcaseCard {
|
||||
/**
|
||||
* Showcase card id.
|
||||
*
|
||||
* @param {string} id
|
||||
*/
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
this.$container = $(`#${this.id}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get showcase card container.
|
||||
*
|
||||
* @returns {jQuery}
|
||||
*/
|
||||
getContainer() {
|
||||
return this.$container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend showcase card with external extensions.
|
||||
*
|
||||
* @param {object} extension
|
||||
*/
|
||||
addExtension(extension) {
|
||||
extension.extend(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* class TaggableField is responsible for providing functionality from bootstrap-tokenfield plugin.
|
||||
* It allows to have taggable fields which are split in separate blocks once you click enter. Values originally saved
|
||||
* in comma split strings.
|
||||
*/
|
||||
export default class TaggableField {
|
||||
/**
|
||||
* @param {string} tokenFieldSelector - a selector which is used within jQuery object.
|
||||
* @param {object} options - extends basic tokenField behavior with additional options such as minLength, delimiter,
|
||||
* allow to add token on focus out action. See bootstrap-tokenfield docs for more information.
|
||||
*/
|
||||
constructor({tokenFieldSelector, options = {}}) {
|
||||
$(tokenFieldSelector).tokenfield(options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* Component which allows to copy regular text to url friendly text
|
||||
*
|
||||
* Usage example in template:
|
||||
*
|
||||
* <input name="source-input"
|
||||
* class="js-link-rewrite-copier-source"> // The original text will be taken from this element
|
||||
* <input name="destination-input"
|
||||
* class="js-link-rewrite-copier-destination"> // Modified text will be added to this input
|
||||
*
|
||||
* in javascript:
|
||||
*
|
||||
* textToLinkRewriteCopier({
|
||||
* sourceElementSelector: '.js-link-rewrite-copier-source'
|
||||
* destinationElementSelector: '.js-link-rewrite-copier-destination',
|
||||
* });
|
||||
*
|
||||
* If the source-input has value "test name" the link rewrite value will be "test-name".
|
||||
* If the source-input has value "test name #$" link rewrite will be "test-name-" since #$
|
||||
* are un allowed characters in url.
|
||||
*
|
||||
* You can also pass additional options to change the event name, or encoding format:
|
||||
*
|
||||
* textToLinkRewriteCopier({
|
||||
* sourceElementSelector: '.js-link-rewrite-copier-source'
|
||||
* destinationElementSelector: '.js-link-rewrite-copier-destination',
|
||||
* options: {
|
||||
* eventName: 'change', // default is 'input'
|
||||
* }
|
||||
* });
|
||||
*
|
||||
*/
|
||||
const textToLinkRewriteCopier = (
|
||||
{
|
||||
sourceElementSelector,
|
||||
destinationElementSelector,
|
||||
options = {eventName: 'input'},
|
||||
},
|
||||
) => {
|
||||
$(document).on(options.eventName, `${sourceElementSelector}`, (event) => {
|
||||
$(destinationElementSelector).val(window.str2url($(event.currentTarget).val(), 'UTF-8'));
|
||||
});
|
||||
};
|
||||
|
||||
export default textToLinkRewriteCopier;
|
||||
285
admin-kalsport/themes/new-theme/js/components/tinymce-editor.js
Normal file
285
admin-kalsport/themes/new-theme/js/components/tinymce-editor.js
Normal file
@@ -0,0 +1,285 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
import {EventEmitter} from './event-emitter';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* This class init TinyMCE instances in the back-office. It is wildly inspired by
|
||||
* the scripts from js/admin And it actually loads TinyMCE from the js/tiny_mce
|
||||
* folder along with its modules. One improvement could be to install TinyMCE via
|
||||
* npm and fully integrate in the back-office theme.
|
||||
*/
|
||||
class TinyMCEEditor {
|
||||
constructor(options) {
|
||||
const opts = options || {};
|
||||
this.tinyMCELoaded = false;
|
||||
if (typeof opts.baseAdminUrl === 'undefined') {
|
||||
if (typeof window.baseAdminDir !== 'undefined') {
|
||||
opts.baseAdminUrl = window.baseAdminDir;
|
||||
} else {
|
||||
const pathParts = window.location.pathname.split('/');
|
||||
pathParts.every((pathPart) => {
|
||||
if (pathPart !== '') {
|
||||
opts.baseAdminUrl = `/${pathPart}/`;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
if (typeof opts.langIsRtl === 'undefined') {
|
||||
opts.langIsRtl = typeof window.lang_is_rtl !== 'undefined' ? window.lang_is_rtl === '1' : false;
|
||||
}
|
||||
this.setupTinyMCE(opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial setup which checks if the tinyMCE library is already loaded.
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
setupTinyMCE(config) {
|
||||
if (typeof tinyMCE === 'undefined') {
|
||||
this.loadAndInitTinyMCE(config);
|
||||
} else {
|
||||
this.initTinyMCE(config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the config and init all TinyMCE editors
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
initTinyMCE(config) {
|
||||
const cfg = {
|
||||
selector: '.rte',
|
||||
plugins: 'align colorpicker link image filemanager table media placeholder lists advlist code table autoresize',
|
||||
browser_spellcheck: true,
|
||||
toolbar1:
|
||||
/* eslint-disable-next-line max-len */
|
||||
'code,colorpicker,bold,italic,underline,strikethrough,blockquote,link,align,bullist,numlist,table,image,media,formatselect',
|
||||
toolbar2: '',
|
||||
language: window.iso_user,
|
||||
external_filemanager_path: `${config.baseAdminUrl}filemanager/`,
|
||||
filemanager_title: 'File manager',
|
||||
external_plugins: {
|
||||
filemanager: `${config.baseAdminUrl}filemanager/plugin.min.js`,
|
||||
},
|
||||
content_style: config.langIsRtl ? 'body {direction:rtl;}' : '',
|
||||
skin: 'prestashop',
|
||||
mobile: {
|
||||
theme: 'mobile',
|
||||
plugins: ['lists', 'align', 'link', 'table', 'placeholder', 'advlist', 'code'],
|
||||
toolbar:
|
||||
/* eslint-disable-next-line max-len */
|
||||
'undo code colorpicker bold italic underline strikethrough blockquote link align bullist numlist table formatselect styleselect',
|
||||
},
|
||||
menubar: false,
|
||||
statusbar: false,
|
||||
relative_urls: false,
|
||||
convert_urls: false,
|
||||
entity_encoding: 'raw',
|
||||
extended_valid_elements: 'em[class|name|id],@[role|data-*|aria-*]',
|
||||
valid_children: '+*[*]',
|
||||
valid_elements: '*[*]',
|
||||
rel_list: [{title: 'nofollow', value: 'nofollow'}],
|
||||
editor_selector: 'autoload_rte',
|
||||
init_instance_callback: () => {
|
||||
this.changeToMaterial();
|
||||
},
|
||||
setup: (editor) => {
|
||||
this.setupEditor(editor);
|
||||
},
|
||||
...config,
|
||||
};
|
||||
|
||||
if (typeof window.defaultTinyMceConfig !== 'undefined') {
|
||||
Object.assign(cfg, window.defaultTinyMceConfig);
|
||||
}
|
||||
|
||||
if (typeof cfg.editor_selector !== 'undefined') {
|
||||
cfg.selector = `.${cfg.editor_selector}`;
|
||||
}
|
||||
|
||||
// Change icons in popups
|
||||
$('body').on('click', '.mce-btn, .mce-open, .mce-menu-item', () => {
|
||||
this.changeToMaterial();
|
||||
});
|
||||
|
||||
window.tinyMCE.init(cfg);
|
||||
this.watchTabChanges(cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup TinyMCE editor once it has been initialized
|
||||
*
|
||||
* @param editor
|
||||
*/
|
||||
setupEditor(editor) {
|
||||
editor.on('loadContent', (event) => {
|
||||
this.handleCounterTiny(event.target.id);
|
||||
});
|
||||
editor.on('change', (event) => {
|
||||
window.tinyMCE.triggerSave();
|
||||
this.handleCounterTiny(event.target.id);
|
||||
});
|
||||
editor.on('blur', () => {
|
||||
window.tinyMCE.triggerSave();
|
||||
});
|
||||
EventEmitter.emit('tinymceEditorSetup', {
|
||||
editor,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* When the editor is inside a tab it can cause a bug on tab switching.
|
||||
* So we check if the editor is contained in a navigation and refresh the editor when its
|
||||
* parent tab is shown.
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
watchTabChanges(config) {
|
||||
$(config.selector).each((index, textarea) => {
|
||||
const translatedField = $(textarea).closest('.translation-field');
|
||||
const tabContainer = $(textarea).closest('.translations.tabbable');
|
||||
|
||||
if (translatedField.length && tabContainer.length) {
|
||||
const textareaLocale = translatedField.data('locale');
|
||||
const textareaLinkSelector = `.nav-item a[data-locale="${textareaLocale}"]`;
|
||||
|
||||
$(textareaLinkSelector, tabContainer).on('shown.bs.tab', () => {
|
||||
const form = $(textarea).closest('form');
|
||||
const editor = window.tinyMCE.get(textarea.id);
|
||||
|
||||
if (editor) {
|
||||
// Reset content to force refresh of editor
|
||||
editor.setContent(editor.getContent());
|
||||
}
|
||||
|
||||
EventEmitter.emit('languageSelected', {
|
||||
selectedLocale: textareaLocale,
|
||||
form,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
EventEmitter.on('languageSelected', (data) => {
|
||||
const textareaLinkSelector = `.nav-item a[data-locale="${data.selectedLocale}"]`;
|
||||
|
||||
$(textareaLinkSelector).click();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the TinyMCE javascript library and then init the editors
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
loadAndInitTinyMCE(config) {
|
||||
if (this.tinyMCELoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.tinyMCELoaded = true;
|
||||
const pathArray = config.baseAdminUrl.split('/');
|
||||
pathArray.splice(pathArray.length - 2, 2);
|
||||
const finalPath = pathArray.join('/');
|
||||
window.tinyMCEPreInit = {};
|
||||
window.tinyMCEPreInit.base = `${finalPath}/js/tiny_mce`;
|
||||
window.tinyMCEPreInit.suffix = '.min';
|
||||
$.getScript(`${finalPath}/js/tiny_mce/tinymce.min.js`, () => {
|
||||
this.setupTinyMCE(config);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace initial TinyMCE icons with material icons
|
||||
*/
|
||||
changeToMaterial() {
|
||||
const materialIconAssoc = {
|
||||
'mce-i-code': '<i class="material-icons">code</i>',
|
||||
'mce-i-none': '<i class="material-icons">format_color_text</i>',
|
||||
'mce-i-bold': '<i class="material-icons">format_bold</i>',
|
||||
'mce-i-italic': '<i class="material-icons">format_italic</i>',
|
||||
'mce-i-underline': '<i class="material-icons">format_underlined</i>',
|
||||
'mce-i-strikethrough': '<i class="material-icons">format_strikethrough</i>',
|
||||
'mce-i-blockquote': '<i class="material-icons">format_quote</i>',
|
||||
'mce-i-link': '<i class="material-icons">link</i>',
|
||||
'mce-i-alignleft': '<i class="material-icons">format_align_left</i>',
|
||||
'mce-i-aligncenter': '<i class="material-icons">format_align_center</i>',
|
||||
'mce-i-alignright': '<i class="material-icons">format_align_right</i>',
|
||||
'mce-i-alignjustify': '<i class="material-icons">format_align_justify</i>',
|
||||
'mce-i-bullist': '<i class="material-icons">format_list_bulleted</i>',
|
||||
'mce-i-numlist': '<i class="material-icons">format_list_numbered</i>',
|
||||
'mce-i-image': '<i class="material-icons">image</i>',
|
||||
'mce-i-table': '<i class="material-icons">grid_on</i>',
|
||||
'mce-i-media': '<i class="material-icons">video_library</i>',
|
||||
'mce-i-browse': '<i class="material-icons">attachment</i>',
|
||||
'mce-i-checkbox': '<i class="mce-ico mce-i-checkbox"></i>',
|
||||
};
|
||||
|
||||
$.each(materialIconAssoc, (index, value) => {
|
||||
$(`.${index}`).replaceWith(value);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the characters counter. This counter is used for front but if you don't want to encounter Validation
|
||||
* problems you should be in sync with the TinyMceMaxLengthValidator PHP class. Both codes must behave the same
|
||||
* way.
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
handleCounterTiny(id) {
|
||||
const textarea = $(`#${id}`);
|
||||
const counter = textarea.attr('counter');
|
||||
const counterType = textarea.attr('counter_type');
|
||||
const editor = window.tinyMCE.get(id);
|
||||
const max = editor.getBody() ? editor.getBody().textContent.length : 0;
|
||||
|
||||
textarea
|
||||
.parent()
|
||||
.find('span.currentLength')
|
||||
.text(max);
|
||||
if (counterType !== 'recommended' && max > counter) {
|
||||
textarea
|
||||
.parent()
|
||||
.find('span.maxLength')
|
||||
.addClass('text-danger');
|
||||
} else {
|
||||
textarea
|
||||
.parent()
|
||||
.find('span.maxLength')
|
||||
.removeClass('text-danger');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default TinyMCEEditor;
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import {EventEmitter} from './event-emitter';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* This class is used to automatically toggle translated fields (displayed with tabs
|
||||
* using the TranslateType Symfony form type).
|
||||
* Also compatible with TranslatableInput changes.
|
||||
*/
|
||||
class TranslatableField {
|
||||
constructor(options) {
|
||||
const opts = options || {};
|
||||
|
||||
this.localeButtonSelector = opts.localeButtonSelector || '.translationsLocales.nav .nav-item a[data-toggle="tab"]';
|
||||
this.localeNavigationSelector = opts.localeNavigationSelector || '.translationsLocales.nav';
|
||||
this.translationFieldSelector = opts.translationFieldSelector || '.translation-field';
|
||||
this.selectedLocale = $('.nav-item a.active', $(this.localeNavigationSelector)).data('locale');
|
||||
|
||||
$('body').on('shown.bs.tab', this.localeButtonSelector, this.toggleLanguage.bind(this));
|
||||
EventEmitter.on('languageSelected', this.toggleFields.bind(this));
|
||||
|
||||
return {
|
||||
localeButtonSelector: this.localeButtonSelector,
|
||||
localeNavigationSelector: this.localeNavigationSelector,
|
||||
translationFieldSelector: this.translationFieldSelector,
|
||||
|
||||
/**
|
||||
* @param {jQuery} form
|
||||
*/
|
||||
refreshFormInputs: (form) => { this.refreshInputs(form); },
|
||||
|
||||
/**
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
getSelectedLocale: () => this.selectedLocale,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param form
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
refreshInputs(form) {
|
||||
EventEmitter.emit('languageSelected', {
|
||||
selectedLocale: this.selectedLocale,
|
||||
form,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch event on language selection to update inputs and other components which depend on the locale.
|
||||
*
|
||||
* @param event
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggleLanguage(event) {
|
||||
const localeLink = $(event.target);
|
||||
const form = localeLink.closest('form');
|
||||
this.selectedLocale = localeLink.data('locale');
|
||||
this.refreshInputs(form);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle all transtation fields to the selected locale
|
||||
*
|
||||
* @param event
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggleFields(event) {
|
||||
this.selectedLocale = event.selectedLocale;
|
||||
$(this.localeNavigationSelector).each((index, navigation) => {
|
||||
const selectedLink = $('.nav-item a.active', navigation);
|
||||
const selectedLocale = selectedLink.data('locale');
|
||||
|
||||
if (this.selectedLocale !== selectedLocale) {
|
||||
$(`.nav-item a[data-locale="${this.selectedLocale}"]`, navigation).tab('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default TranslatableField;
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Open Software License (OSL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/OSL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
||||
*/
|
||||
|
||||
import {EventEmitter} from './event-emitter';
|
||||
|
||||
const {$} = window;
|
||||
|
||||
/**
|
||||
* This class is used to automatically toggle translated inputs (displayed with one
|
||||
* input and a language selector using the TranslatableType Symfony form type).
|
||||
* Also compatible with TranslatableField changes.
|
||||
*/
|
||||
class TranslatableInput {
|
||||
constructor(options) {
|
||||
const opts = options || {};
|
||||
|
||||
this.localeItemSelector = opts.localeItemSelector || '.js-locale-item';
|
||||
this.localeButtonSelector = opts.localeButtonSelector || '.js-locale-btn';
|
||||
this.localeInputSelector = opts.localeInputSelector || '.js-locale-input';
|
||||
this.selectedLocale = $(this.localeItemSelector).data('locale');
|
||||
|
||||
$('body').on(
|
||||
'click',
|
||||
this.localeItemSelector,
|
||||
this.toggleLanguage.bind(this),
|
||||
);
|
||||
EventEmitter.on('languageSelected', this.toggleInputs.bind(this));
|
||||
|
||||
return {
|
||||
localeItemSelector: this.localeItemSelector,
|
||||
localeButtonSelector: this.localeButtonSelector,
|
||||
localeInputSelector: this.localeInputSelector,
|
||||
|
||||
/**
|
||||
* @param {jQuery} form
|
||||
*/
|
||||
refreshFormInputs: (form) => { this.refreshInputs(form); },
|
||||
|
||||
/**
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
getSelectedLocale: () => this.selectedLocale,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {jQuery} form
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
refreshInputs(form) {
|
||||
if (!this.selectedLocale) {
|
||||
return;
|
||||
}
|
||||
|
||||
EventEmitter.emit('languageSelected', {
|
||||
selectedLocale: this.selectedLocale,
|
||||
form,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch event on language selection to update inputs and other components which depend on the locale.
|
||||
*
|
||||
* @param event
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggleLanguage(event) {
|
||||
const localeItem = $(event.target);
|
||||
const form = localeItem.closest('form');
|
||||
this.selectedLocale = localeItem.data('locale');
|
||||
this.refreshInputs(form);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle all translatable inputs in form in which locale was changed
|
||||
*
|
||||
* @param {Event} event
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
toggleInputs(event) {
|
||||
const {form} = event;
|
||||
this.selectedLocale = event.selectedLocale;
|
||||
const localeButton = form.find(this.localeButtonSelector);
|
||||
const changeLanguageUrl = localeButton.data('change-language-url');
|
||||
|
||||
localeButton.text(this.selectedLocale);
|
||||
form.find(this.localeInputSelector).addClass('d-none');
|
||||
form
|
||||
.find(`${this.localeInputSelector}.js-locale-${this.selectedLocale}`)
|
||||
.removeClass('d-none');
|
||||
|
||||
if (changeLanguageUrl) {
|
||||
this.saveSelectedLanguage(changeLanguageUrl, this.selectedLocale);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save language choice for employee forms.
|
||||
*
|
||||
* @param {String} changeLanguageUrl
|
||||
* @param {String} selectedLocale
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
saveSelectedLanguage(changeLanguageUrl, selectedLocale) {
|
||||
$.post({
|
||||
url: changeLanguageUrl,
|
||||
data: {
|
||||
language_iso_code: selectedLocale,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default TranslatableInput;
|
||||
Reference in New Issue
Block a user