Add X13 WebP module for image conversion to next-generation formats
- Implemented the X13Webp class with core functionalities for converting images to WebP format. - Added support for different PHP versions and defined constants for versioning. - Included translation strings for various user interface elements and messages. - Created XML file for module versioning.
This commit is contained in:
56
modules/x13webp/views/js/front/x13webp.front.js
Normal file
56
modules/x13webp/views/js/front/x13webp.front.js
Normal file
@@ -0,0 +1,56 @@
|
||||
$(document).ready(() => {
|
||||
let x13images = [];
|
||||
|
||||
$("img").each(function () {
|
||||
const imgSrc = $(this).attr("data-src") ?? $(this).attr("data-original") ?? $(this).attr("src");
|
||||
|
||||
if (!imgSrc) return;
|
||||
if (imgSrc.includes(".webp")) return;
|
||||
|
||||
if ($(this).siblings("source").length && $(this).siblings("source").attr("srcset") !== undefined) {
|
||||
if ($(this).siblings("source").attr("srcset").includes(".webp")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
x13images.push(imgSrc.trim());
|
||||
});
|
||||
|
||||
$("[style]").each(function () {
|
||||
const bgImage = $(this).css("background-image");
|
||||
|
||||
if (bgImage.includes(".webp") || (!bgImage.includes(".jpg") && !bgImage.includes(".png"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
let image = $(this)
|
||||
.css("background-image")
|
||||
.replace(/url\("([^"]+)"\)/, "$1");
|
||||
x13images.push(image.trim());
|
||||
});
|
||||
|
||||
$("#product #thumbs_list a.fancybox").each(function () {
|
||||
const href = $(this).attr("href");
|
||||
if (href.length) {
|
||||
x13images.push(href.trim());
|
||||
}
|
||||
});
|
||||
$("#product .images-container .thumb").each(function () {
|
||||
const medium = $(this).data("image-medium-src");
|
||||
const large = $(this).data("image-large-src");
|
||||
if (typeof medium !== 'undefined') {
|
||||
x13images.push(medium.trim());
|
||||
}
|
||||
if (typeof large !== 'undefined') {
|
||||
x13images.push(large.trim());
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: x13webp_ajax_convert_url,
|
||||
method: "POST",
|
||||
data: {
|
||||
x13images,
|
||||
},
|
||||
});
|
||||
});
|
||||
171
modules/x13webp/views/js/front/x13webp.picture.js
Normal file
171
modules/x13webp/views/js/front/x13webp.picture.js
Normal file
@@ -0,0 +1,171 @@
|
||||
$(() => {
|
||||
x13webp.fixProductThumbs();
|
||||
if (!x13webpIsPs16) {
|
||||
x13webp.addStylesheet();
|
||||
}
|
||||
x13webp.observe();
|
||||
});
|
||||
|
||||
$(window).on('hashchange', function () {
|
||||
if (!x13webpIsPs16) return;
|
||||
|
||||
setTimeout(function () {
|
||||
let thumb = $('#thumbs_list_frame li:visible:first');
|
||||
if (thumb.length === 0) return;
|
||||
if (thumb.find('picture').length === 0) return;
|
||||
|
||||
let img = thumb.find('img').attr('data-original') ?? thumb.find('img').attr('src');
|
||||
let source = thumb.find('source').attr('srcset');
|
||||
|
||||
$('#' + x13webp.themeSelectors.jsQvProductCover).attr('src', img.replace('-cart_default', '-large_default'));
|
||||
$('#' + x13webp.themeSelectors.jsQvProductCover).siblings('source').attr('srcset', source.replace('-cart_default', '-large_default'));
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
const x13webp = {
|
||||
themeSelectors: {
|
||||
jsQvProductCover: x13webpIsPs16 ? "bigpic" : "js-qv-product-cover",
|
||||
jsModalProductCover: "js-modal-product-cover",
|
||||
jsThumb: "js-thumb",
|
||||
jsModalThumb: "js-modal-thumb",
|
||||
},
|
||||
|
||||
addStylesheet: () => {
|
||||
let thumbHover = "." + x13webp.themeSelectors.jsThumb + ":hover";
|
||||
let thumbSelected = "." + x13webp.themeSelectors.jsThumb + ".selected";
|
||||
let thumb = document.querySelector(thumbSelected);
|
||||
|
||||
if (!thumb) return;
|
||||
|
||||
thumb = getComputedStyle(thumb);
|
||||
let thumbBorder = {
|
||||
style: thumb.borderBlockStyle,
|
||||
width: thumb.borderBlockWidth,
|
||||
color: thumb.borderBlockColor,
|
||||
};
|
||||
|
||||
let css =
|
||||
"picture" +
|
||||
thumbSelected +
|
||||
", picture" +
|
||||
thumbHover +
|
||||
", " +
|
||||
"picture" +
|
||||
thumbSelected.replace(
|
||||
x13webp.themeSelectors.jsThumb,
|
||||
x13webp.themeSelectors.jsModalThumb
|
||||
) +
|
||||
", picture" +
|
||||
thumbHover.replace(
|
||||
x13webp.themeSelectors.jsThumb,
|
||||
x13webp.themeSelectors.jsModalThumb
|
||||
) +
|
||||
" { border: none !important; outline-style: " +
|
||||
thumbBorder.style +
|
||||
" !important; outline-color: " +
|
||||
thumbBorder.color +
|
||||
" !important; outline-width: " +
|
||||
thumbBorder.width +
|
||||
" !important; outline-offset: -" +
|
||||
thumbBorder.width +
|
||||
" !important;}",
|
||||
head = document.head || document.getElementsByTagName("head")[0],
|
||||
style = document.createElement("style");
|
||||
|
||||
head.appendChild(style);
|
||||
|
||||
style.type = "text/css";
|
||||
if (style.styleSheet) {
|
||||
// This is required for IE8 and below.
|
||||
style.styleSheet.cssText = css;
|
||||
} else {
|
||||
style.appendChild(document.createTextNode(css));
|
||||
}
|
||||
},
|
||||
|
||||
replacePictureSource: (target, source) => {
|
||||
target.setAttribute("srcset", source);
|
||||
},
|
||||
|
||||
addAttributesToPicture: (target, classArray, dataArray = {}) => {
|
||||
target.style.display = "inline-block";
|
||||
target.classList.add(...classArray);
|
||||
|
||||
Object.entries(dataArray).forEach(([key, value]) => {
|
||||
target.dataset[key] = value;
|
||||
});
|
||||
},
|
||||
|
||||
fixProductThumbs: () => {
|
||||
const body = document.querySelector("body").getAttribute("id");
|
||||
|
||||
if (body !== "product") return;
|
||||
|
||||
const thumbs = [
|
||||
...document.querySelectorAll("." + x13webp.themeSelectors.jsThumb),
|
||||
];
|
||||
const modalThumbs = [
|
||||
...document.querySelectorAll("." + x13webp.themeSelectors.jsModalThumb),
|
||||
];
|
||||
|
||||
const allThumbs = [...thumbs, ...modalThumbs];
|
||||
|
||||
allThumbs.forEach((thumb) => {
|
||||
if (!thumb.parentElement) return;
|
||||
if (thumb.parentElement.tagName !== "PICTURE") return;
|
||||
|
||||
const target = thumb.parentElement;
|
||||
const classArray = thumb.classList;
|
||||
const isModal = classArray.contains(x13webp.themeSelectors.jsModalThumb);
|
||||
const dataArray = Object.assign({}, thumb.dataset);
|
||||
|
||||
x13webp.addAttributesToPicture(target, classArray, dataArray);
|
||||
|
||||
thumb.className = isModal
|
||||
? x13webp.themeSelectors.jsModalThumb + "-fix"
|
||||
: x13webp.themeSelectors.jsThumb + "-fix";
|
||||
});
|
||||
},
|
||||
|
||||
observe: () => {
|
||||
const pictureTagObserver = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (!mutation.target.parentElement) return;
|
||||
if (mutation.target.parentElement.tagName !== "PICTURE") return;
|
||||
|
||||
const mutationClass = mutation.target.classList;
|
||||
|
||||
if (
|
||||
mutationClass.contains(x13webp.themeSelectors.jsQvProductCover) ||
|
||||
mutationClass.contains(x13webp.themeSelectors.jsModalProductCover) ||
|
||||
mutation.target.getAttribute("id") ===
|
||||
x13webp.themeSelectors.jsQvProductCover
|
||||
) {
|
||||
const target = mutation.target.parentElement.querySelector("source");
|
||||
let source =
|
||||
mutation.target.getAttribute("data-original") ??
|
||||
mutation.target.getAttribute("src");
|
||||
source = source.replace(/(\.jpg)|(\.png)/, ".webp");
|
||||
|
||||
x13webp.replacePictureSource(target, source);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mutationClass.contains(x13webp.themeSelectors.jsThumb + "-fix")) {
|
||||
const target = mutation.target.parentElement;
|
||||
const classArray = mutation.target.classList;
|
||||
|
||||
x13webp.addAttributesToPicture(target, classArray);
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const allPictureTags = document.querySelectorAll("img");
|
||||
|
||||
allPictureTags.forEach((pictureTag) => {
|
||||
pictureTagObserver.observe(pictureTag, { attributes: true });
|
||||
});
|
||||
},
|
||||
};
|
||||
15
modules/x13webp/views/js/lightbox.min.js
vendored
Normal file
15
modules/x13webp/views/js/lightbox.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
327
modules/x13webp/views/js/x13filemanager.admin.js
Normal file
327
modules/x13webp/views/js/x13filemanager.admin.js
Normal file
@@ -0,0 +1,327 @@
|
||||
let pause_othres_conversion = true;
|
||||
|
||||
$(document).ready(() => {
|
||||
|
||||
$('.list-files:not(.is-loading)').on('click', 'li.dir:not(.is-loaded) p', function (e) {
|
||||
|
||||
if ($(e.target).is('input')) return;
|
||||
$('.list-files').addClass('is-loading');
|
||||
$(this).addClass('loading');
|
||||
ajaxFileManager($(this).parent());
|
||||
|
||||
});
|
||||
|
||||
$('.list-files:not(.is-loading)').on('click', 'li.dir.is-loaded > p', function (e) {
|
||||
|
||||
if ($(e.target).is('input')) return;
|
||||
$(this).parent().toggleClass(['is-open', 'is-closed']);
|
||||
toggleState($(this).find('.state'), $(this).parent().hasClass('is-open'));
|
||||
|
||||
});
|
||||
|
||||
$('.list-files').on('change', 'input[type="checkbox"][name="others_item"]', function () {
|
||||
|
||||
if ($(this).prop('checked')) {
|
||||
|
||||
$('.btn-item-start-others').attr('disabled', false);
|
||||
|
||||
} else {
|
||||
|
||||
$('.btn-item-start-others').attr('disabled', $('input[name="others_item"]:checked:not(:disabled)').length ? false : true);
|
||||
|
||||
}
|
||||
|
||||
const li = $(this).closest('li');
|
||||
|
||||
if (li.length && li.hasClass('dir')) {
|
||||
|
||||
li.find('input:not(:disabled)').prop('checked', $(this).prop('checked'));
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$('.btn-item-start-others').on('click',function(){
|
||||
|
||||
actionStartConversion();
|
||||
|
||||
let items = [];
|
||||
|
||||
$('.list-files').find('input[name="others_item"]:checked:not(:disabled)').each(function(){
|
||||
items.push($(this).val())
|
||||
});
|
||||
|
||||
ajaxGenerateOthersItem(items)
|
||||
|
||||
});
|
||||
|
||||
$('.btn-item-pause-others').on('click', function () {
|
||||
|
||||
actionPauseConversion();
|
||||
|
||||
});
|
||||
|
||||
$('.btn-item-refresh-others').on('click', function(){
|
||||
|
||||
$.ajax({
|
||||
url: x13webp_refresh_others_url,
|
||||
method: 'POST',
|
||||
}).done((resp) => {
|
||||
|
||||
if(resp.length){
|
||||
|
||||
const content = JSON.parse(resp);
|
||||
|
||||
if(content.error){
|
||||
|
||||
alert(content.error);
|
||||
actionPauseConversion();
|
||||
|
||||
} else if(content.items.length){
|
||||
|
||||
resetProgressItem();
|
||||
actionStartConversion();
|
||||
|
||||
$(content.items).each(function(){
|
||||
const input = getInputByValue(this)
|
||||
|
||||
if (input.length) input.attr('disabled', false);
|
||||
|
||||
});
|
||||
|
||||
ajaxGenerateOthersItem(content.items);
|
||||
|
||||
} else {
|
||||
|
||||
alert(x13webp_unexpected_error);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
const getInputByValue = (val) => {
|
||||
return $('.list-files input[value="' + val + '"]');
|
||||
}
|
||||
|
||||
const resetProgressItem = () => {
|
||||
|
||||
const progress_bar = $('#tab-x13wepb-others').find('.progress-bar');
|
||||
progress_bar.attr('aria-valuenow', 0);
|
||||
const totals = $('#tab-x13wepb-others').find('.images-done-total');
|
||||
totals.find('.done').text(0);
|
||||
progress_bar.parent().removeClass('is-done')
|
||||
progress_bar.find('.progressbar-inner').text(`0%`);
|
||||
progress_bar.css('width', '0%');
|
||||
|
||||
}
|
||||
|
||||
const actionStartConversion = () => {
|
||||
|
||||
pause_othres_conversion = false;
|
||||
$('#form-tabs').find('li:not(.active)').tooltip('enable').find('a').addClass('disabled');
|
||||
$('.btn-item-start-others').addClass('hidden').attr('disabled', true).parent().tooltip('disable');
|
||||
$('.btn-item-refresh-others').addClass('hidden').attr('disabled', true);
|
||||
$('.btn-item-pause-others').removeClass('hidden').attr('disabled', false);
|
||||
|
||||
}
|
||||
|
||||
const actionPauseConversion = () => {
|
||||
|
||||
pause_othres_conversion = true;
|
||||
$('#form-tabs').find('li:not(.active)').tooltip('disable').find('a').removeClass('disabled');
|
||||
const disable_button = $('input[name="others_item"]:checked:not(:disabled)').length ? false : true;
|
||||
$('.btn-item-start-others').removeClass('hidden').attr('disabled', disable_button).parent().tooltip(disable_button ? 'enable' : 'disable');
|
||||
$('.btn-item-refresh-others').removeClass('hidden').attr('disabled', false);
|
||||
$('.btn-item-pause-others').addClass('hidden').attr('disabled', true);
|
||||
|
||||
}
|
||||
|
||||
const ajaxGenerateOthersItem = (items) => {
|
||||
|
||||
if (!pause_othres_conversion && items.length) {
|
||||
|
||||
$.ajax({
|
||||
url: x13webp_generate_others_item_url,
|
||||
method: 'POST',
|
||||
data: {
|
||||
item: items[0]
|
||||
}
|
||||
}).done((resp) => {
|
||||
|
||||
if(resp.length){
|
||||
const output = JSON.parse(resp);
|
||||
if(output && !output.error){
|
||||
|
||||
if (output.dir) {
|
||||
|
||||
if(output.complete){
|
||||
|
||||
const input = getInputByValue(items[0]);
|
||||
if (input.length) input.attr('disabled', true).parent().addClass('disabled');
|
||||
items.splice(0, 1);
|
||||
|
||||
} else {
|
||||
|
||||
const input = getInputByValue(output.image);
|
||||
if (input.length) input.attr('disabled', true).parent().addClass('disabled');
|
||||
|
||||
const index = items.indexOf(output.image);
|
||||
if (index !== -1) {
|
||||
items.splice(index, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
const input = getInputByValue(items[0]);
|
||||
if (input.length) input.attr('disabled', true).parent().addClass('disabled');
|
||||
|
||||
items.splice(0, 1);
|
||||
|
||||
}
|
||||
|
||||
const done = $('#tab-x13wepb-others').find('.images-done-total .done').text();
|
||||
if(!output.complete){
|
||||
addOthersLog(`<p class="log-li ${output.warning ? 'has-warning' : ''}">${output.object_name} <strong>#${parseInt(done) + 1}</strong>: <span class="log-format">WebP [${output.image}]</span> <span class="log log-${output.success ? 'success' : 'danger'}">${output.warning ? output.warning : x13webp_success_alert}</span></p>`, output.warning);
|
||||
}
|
||||
|
||||
increaseProgressItem()
|
||||
|
||||
if (items.length) {
|
||||
ajaxGenerateOthersItem(items)
|
||||
} else {
|
||||
actionPauseConversion()
|
||||
}
|
||||
|
||||
if ($('#x13webp-delete-all-webp').hasClass('hidden')) {
|
||||
|
||||
$('#x13webp-delete-all-webp').removeClass('hidden').siblings('.help-block').addClass('hidden');
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
actionPauseConversion()
|
||||
addOthersLog(`<p class="log-li"><span class="log log-danger">${output.error}</span></p>`, true);
|
||||
}
|
||||
} else {
|
||||
actionPauseConversion()
|
||||
addOthersLog(`<p class="log-li"><span class="log log-danger">${x13webp_unexpected_error}</span></p>`, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const addOthersLog = (log, warning = false) => {
|
||||
|
||||
if ($('.x13webp-log-info').parent().hasClass('hidden')) $('.x13webp-log-info').parent().removeClass('hidden')
|
||||
if (log) $('.x13webp-log-info').prepend(log);
|
||||
if (warning && $('#x13webp-log-warning').hasClass('hidden')) $('#x13webp-log-warning').removeClass('hidden');
|
||||
|
||||
}
|
||||
|
||||
const increaseProgressItem = () => {
|
||||
|
||||
const progress_bar = $('#tab-x13wepb-others').find('.progress-bar');
|
||||
progress_bar.attr('aria-valuenow', parseInt(progress_bar.attr('aria-valuenow')) + 1);
|
||||
const percent = parseFloat(progress_bar.attr('aria-valuenow') * 100 / progress_bar.attr('aria-valuemax')).toFixed(2);
|
||||
|
||||
const totals = $('#tab-x13wepb-others').find('.images-done-total');
|
||||
|
||||
totals.find('.done').text(progress_bar.attr('aria-valuenow'));
|
||||
|
||||
if (totals.find('.total').text() == totals.find('.done').text() && !progress_bar.parent().hasClass('is-done')) {
|
||||
|
||||
progress_bar.parent().addClass('is-done')
|
||||
|
||||
}
|
||||
progress_bar.find('.progressbar-inner').text(`${percent}%`);
|
||||
progress_bar.css('width', percent + '%');
|
||||
|
||||
}
|
||||
|
||||
const toggleState = (state, open) => $(state).find('i').toggleClass('icon-folder').toggleClass('icon-folder-open');
|
||||
|
||||
const ajaxFileManager = (li) => {
|
||||
|
||||
li.addClass(['is-open', 'is-loaded']);
|
||||
|
||||
$.ajax({
|
||||
url: x13webp_file_manager_url,
|
||||
method: 'POST',
|
||||
data: {
|
||||
file: li.data('file')
|
||||
}
|
||||
}).done((resp) => {
|
||||
|
||||
if (resp.length) {
|
||||
|
||||
const content = JSON.parse(resp);
|
||||
|
||||
if (content.error) {
|
||||
|
||||
alert(content.error);
|
||||
|
||||
} else if (content.tree.length) {
|
||||
|
||||
toggleState(li.find('.state'), false);
|
||||
|
||||
let ul = '<ul>';
|
||||
|
||||
$(content.tree).each(function(){
|
||||
ul += `<li data-file="${li.data('file')}/${this.name}" ${this.type == 'dir' ? 'class="dir"' : ''}>`;
|
||||
ul += `<p ${this.exists && this.type == 'dir' ? 'data-toggle="tooltip" title="'+x13webp_empty_folder+'"' : ''}>`;
|
||||
|
||||
if(this.type == 'dir'){
|
||||
ul += `<span class="state"><i class="icon-folder"></i></span>`;
|
||||
}
|
||||
if (li.find('p input').prop('checked') && $('.btn-item-start-others').attr('disabled') == true) {
|
||||
$('.btn-item-start-others').attr('disabled', false);
|
||||
}
|
||||
const props = this.exists ?
|
||||
this.type == 'dir' ?
|
||||
'disabled' :
|
||||
'checked disabled':
|
||||
li.find('p input').prop('checked') ?
|
||||
'checked' :
|
||||
'';
|
||||
|
||||
ul += `<input type="checkbox" name="others_item" value="${li.data('file')}/${this.name}" ${props}>`;
|
||||
ul += this.name;
|
||||
ul += `</p>`;
|
||||
ul += `</li>`;
|
||||
|
||||
})
|
||||
|
||||
ul += '</ul>';
|
||||
|
||||
li.append(ul);
|
||||
|
||||
li.find('.dir p').tooltip('enable');
|
||||
|
||||
$('.list-files').removeClass('is-loading');
|
||||
|
||||
} else {
|
||||
|
||||
li.append('<ul class="empty"><li>..</li></ul>');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
li.find('.loading').removeClass('loading');
|
||||
});
|
||||
|
||||
}
|
||||
1094
modules/x13webp/views/js/x13webp.admin.js
Normal file
1094
modules/x13webp/views/js/x13webp.admin.js
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user