🏠 Home 

Greasy Fork is available in English.

AliExpress Improve

Разные мелкие улучшения AliExpress: подсчёт общей цены, возвращение breadcrumb на верх

// ==UserScript==
// @name        AliExpress Improve
// @description Разные мелкие улучшения AliExpress: подсчёт общей цены, возвращение breadcrumb на верх
// @version     1.9.4
// @author      BaNru
// @run-at      document-end
// @include     https://*.aliexpress.com/*
// @match       https://*.aliexpress.com/*
// @grant       GM_xmlhttpRequest
// @namespace https://greasyfork.org/users/374664
// ==/UserScript==
// Глобавльная переменная URLSearchParams
var url = new URLSearchParams(document.location.search);
/* Страница товара */
if(~document.location.href.indexOf('/item/')){
// Регулярка получения цен из строки
var REGEXP = new RegExp(/[\d\s]+(?:\.|,)\d+/),
REGEXP2 = new RegExp(/\d+/),
TOTALPRICE = 0;
// Вытаскиваем цены из строки и преобразуем в числа
function normaliseInt(str){
return parseFloat(
( str.match(REGEXP) && str.match(REGEXP)[0] || str.match(REGEXP2) && str.match(REGEXP2)[0] || 0	).replace(/\s/,'').replace(',', '.')
);
}
// Основная функция подсчёта
function RunTotalPrise() {
// Основная цена
var price = document.querySelector('.product-price-value[itemprop="price"]');
if (price && (price.textContent.match(REGEXP) || price.textContent.match(REGEXP2))) {
price = normaliseInt(price.textContent);
} else {
price = 0;
}
// Доставка
var shippingPrice = document.querySelector('.product-shipping-price .bold');
if (shippingPrice && (shippingPrice.textContent.match(REGEXP) || shippingPrice.textContent.match(REGEXP2))) {
shippingPrice = normaliseInt(shippingPrice.textContent);
} else {
shippingPrice = 0;
}
// Высчитываем
if (price) {
var INPUT_ = document.querySelector('.product-number-picker input').value;
if (shippingPrice) {
return (price * INPUT_ + shippingPrice).toFixed(2);
} else {
return (price * INPUT_).toFixed(2);
}
}
return 0;
}
// Функция вывода цен на страницу
function ReloadTotalPrise() {
TOTALPRICE = RunTotalPrise();
document.querySelector('.USER_totalPrice').textContent = 'Общая сумма: ' + TOTALPRICE;
}
// Отрисовываем блок для вывода цены и кнопку "Пересчитать"
document.querySelector('.product-action').insertAdjacentHTML('beforebegin',
'<span class="USER_totalPrice" style="color:#FF4747;font:bold 1.2em/2em serif;padding-right:20px;">Общая сумма: ' + RunTotalPrise() + '</span><span class="USER_RunTotalPrice" style="background:#FF4747;color:#FFF;cursor:pointer;padding:2px 10px;">Пересчитать</span>');
// Создаём блок для подсчёта за единицу
document.querySelector('.product-sku').insertAdjacentHTML('afterend','<small class="USER_SiglePrice" style="top:-6px;position:relative;"></small>');
// Клик по кнопки "Пересчитать"
document.querySelector('.USER_RunTotalPrice').addEventListener('click', ReloadTotalPrise);
// Инициализация скрипта подсчёта при выборе характеристик товара и количества
// Отслеживание изменения доставки пользователем не предусмотрено
document.querySelectorAll('.product-quantity button,.sku-property-item').forEach(item => {
item.addEventListener('click', e=>{
setTimeout(()=>{
ReloadTotalPrise();
// Подсчёт за единицу. Пока оставим тут.
if(e.target.textContent.match(REGEXP2)){
document.querySelector('.USER_SiglePrice').textContent = parseFloat( TOTALPRICE / e.target.textContent.match(REGEXP2)[0] ).toFixed(2);
}
}, 500); // Увеличить цифру 2+ раза, если не будет успевать считать
});
});
// Возавращение breadcrumb (хлебные крошек, категорий) в верх страницы
var breadcrumb = document.querySelector('.breadcrumb'),
productMain = document.querySelector('.product-main');
if(breadcrumb && productMain){
productMain.insertAdjacentHTML('afterbegin', '<style>.breadcrumb_ {text-align: center; margin: -15px 0 15px;}.breadcrumb_ a {padding: 0 5px;color:#666;font-size:0.8em;} .breadcrumb_ a:hover {color:#ff4747}</style><div class="breadcrumb_"></div>');
var breadcrumb_ = document.querySelector('.breadcrumb_');
breadcrumb.querySelectorAll('a').forEach( function(element) {
let el = element.cloneNode(true);
breadcrumb_.append(el);
});
}
// Показать оригинальное (на английском) название
// ?isOrigTitle=true
if(!document.querySelector('.product-title-switch')){
url.set("isOrigTitle", "true");
// Отрисовываем ссылку переключения
document.querySelector('.product-title').insertAdjacentHTML('afterend','<div class="product-title-switch"><a href="'+ window.location.pathname + '?' + url.toString() +'"><svg class="svg-icon m product-title-icon" aria-hidden="true"><use xlink:href="#icon-translate"></use></svg>Посмотреть оригинальное название</a></div>');
}
}
/* / Страница товара */
// Дополнительный поиск
var breadcrumb_search = document.querySelector('.product-container .nav-breadcrumb');
if (breadcrumb_search) {
breadcrumb_search.insertAdjacentHTML('afterend', '<div class="next-input next-small""><input placeholder="Дополнить" autocomplete="off" value="" class="AEsearch"></div>')
var AEsearch = document.querySelector('.AEsearch');
AEsearch.addEventListener('keyup', e => {
if (e.keyCode == 13) {
let oldS = url.get("SearchText");
oldS = oldS ? oldS + "+" : "";
url.delete("SearchText");
var u = window.location.pathname;
if (~document.location.href.indexOf('w/wholesale')) {
oldS = u.replace('/w/wholesale-', '').replace('.html', '') + '+';
u = '/wholesale';
}
url.set("SearchText", oldS + e.target.value);
window.location.href = u + '?' + url.toString();
}
})
}
// Переключение на старый дизайн
var navtop = document.querySelector('#nav-global');
url.delete("switch_new_app");
url.set("switch_new_app", 'n');
navtop.insertAdjacentHTML('afterbegin', `<style>
.ng-item-wrap.oldD a {
background: #ff4747;
color:#fff;
margin: 0px 5px;
display: inline-block;
padding: 0 10px;
font-weight: bold;
}
.ng-item-wrap.oldD a:hover {
background: #a63c24;
color:#fff;
}
</style>
<div class="ng-item-wrap oldD"><div class="ng-item"><a href="${window.location.pathname}?${url.toString()}">&#8822; старый дизайна</a></div></div>
`);
// Скрытие надоедливой Евы
document.querySelector('body').insertAdjacentHTML('afterend', `<style>
#J_xiaomi_dialog {visibility: hidden;bottom: 20px!important;}
#J_xiaomi_dialog .J_weak, #J_xiaomi_dialog .J_weak:hover {
width: auto;
height: auto;
background: transparent;
box-shadow: none;
}
#J_xiaomi_dialog .J_weak .alime-avatar {
width: 32px !important;
height: auto;
opacity: 0.5;
transition: all;
position:relative;
top:0;
}
#J_xiaomi_dialog .J_weak .alime-avatar:hover {
opacity: 1;
}
#J_xiaomi_dialog .J_weak .alime-text {
display:none;
}
</style>`);
window.onload = function() {
var eva = document.querySelector('#J_xiaomi_dialog');
if (eva) {
var eva2 = eva.querySelector('.close-icon');
if (eva2) {
eva2.click();
setTimeout(() => { eva.style.visibility = "visible"; }, 2000);
}
}
}
/* Отключение aotoplay у карусели при добавление в корзину */
/* Спасибо за помощь Джентльменам */
/*
НЕ РАБОТАЕТ в Greasemonkey! Он не хочет читать Object.key у элемента.
Проверена работа в Tampermonkey
*/
function stopSlider() {
var tI = 0;
var timerCard = setInterval(() => {
tI > 20 ? clearInterval(timerCard) : tI++; // Останавливаем таймер, если элемент не найден в течение 10 секунд
// console.log('Ищем слайдер');
if (document.querySelector('.next-slick')) {
setTimeout(()=>{
document.querySelector('.next-slick')[Object.keys(document.querySelector('.next-slick'))[0]].alternate.memoizedProps.children.props.autoplay = false;
}, 500); // Хак на дни распродаж. Если не поможет, то увеличить в x2-x4 раза и на медленных компьютерах
clearInterval(timerCard);
}
}, 500);
}
document.querySelector('.product-action').addEventListener('click', (e) => {
if (e.target.classList.contains('addcart')) {
if (document.querySelector('.product-action .addcart-wrap:not([aria-expanded]) button')) {
stopSlider();
}
}
if (e.target.closest('.add-wishlist-wrap')) {
stopSlider();
}
});
// Номера треков на странице заказов
// Генерация цветов (на входе 0-255 - яркость цвета)
function randomColor(brightness) {
function randomChannel(brightness) {
var r = 255 - brightness;
var n = 0 | ((Math.random() * r) + brightness);
var s = n.toString(16);
return (s.length == 1) ? '0' + s : s;
}
return '#' + randomChannel(brightness) + randomChannel(brightness) + randomChannel(brightness);
}
// Удаление дубликатов в массиве (треков)
function removeDublicate(tracknumber) {
return tracknumber.filter((v, i) => tracknumber.indexOf(v) === i);
}
// Получение тректов
function gettrack(el, ordernumber, refresh) {
return new Promise((resolve, reject) => {
var inLS = localStorage.getItem(ordernumber);
if (inLS && !refresh) {
console.log('local', JSON.parse(inLS));
return resolve([el, JSON.parse(inLS)]);
}
GM_xmlhttpRequest({
method: "GET",
url: 'https://track.aliexpress.com/logisticsdetail.htm?tradeId=' + ordernumber,
withCredentials: true,
onload: response => {
var tracknumber = [];
if (/"logisticsNo":"(.*?)"/.exec(response.responseText)) {
tracknumber.push(/"logisticsNo":"(.*?)"/.exec(response.responseText)[1]);
}
if (/"interMailNo":"(.*?)"/.exec(response.responseText)) {
tracknumber.push(/"interMailNo":"(.*?)"/.exec(response.responseText)[1]);
}
if (/"lgOrderCode":"(.*?)"/.exec(response.responseText)) {
tracknumber.push(/"lgOrderCode":"(.*?)"/.exec(response.responseText)[1]);
}
if (/"realMailNo":"(.*?)"/.exec(response.responseText)) {
tracknumber.push(/"realMailNo":"(.*?)"/.exec(response.responseText)[1]);
}
if (/"mailNo":"(.*?)"/.exec(response.responseText)) {
tracknumber.push(/"mailNo":"(.*?)"/.exec(response.responseText)[1]);
}
if (tracknumber.length > 0) {
tracknumber = removeDublicate(tracknumber);
localStorage.setItem(ordernumber, JSON.stringify(tracknumber));
return resolve([el, tracknumber]);
} else {
return resolve([el, []]);
}
},
onerror: error => {
console.log(error);
return reject('Ошибка получения страницы отслеживания');
}
});
});
}
// Вставка треков на страницу (с поиском и подсветкой дублей/консолидированных)
function insertTrack(el, track) {
var thisBTN = el.closest('.order-item-wraper').querySelector('.order-action button');
track.forEach(c => {
var color = 'transparent';
document.querySelectorAll('.inproveTrack').forEach(ie => {
if (ie.textContent == c) {
if(color == 'transparent'){color = randomColor(160);}
ie.style.backgroundColor = color;
}
});
thisBTN.insertAdjacentHTML('afterend', `
<a class="inproveTrack" href="https://gdeposylka.ru/${c}" target="_blank" style="background:${color};">${c}</a>
`);
});
var trackrefresh = document.createElement('span');
trackrefresh.className = 'trackrefresh';
trackrefresh.textContent = '↺';
trackrefresh.addEventListener('click', () => {
el.closest('.order-item-wraper').querySelectorAll('.inproveTrack, .trackrefresh').forEach(r => {
r.remove();
});
gettrack(el, el.textContent.trim(), true).then(e => {
insertTrack(e[0], e[1]);
});
});
thisBTN.parentNode.insertBefore(trackrefresh, thisBTN.nextSibling);
}
// Запуск скрипта отображения треков
if (~document.location.href.indexOf('orderList.htm')) {
document.querySelector('body').insertAdjacentHTML('afterend', `<style>
.inproveTrack {
font-size: .8em;
display: inline-block;
position: relative;top: -6px;
padding: 1px 5px 2px;
}
.trackrefresh {
float: right;
font-size: 1.3em;
cursor: pointer;
margin-top: -7px;
}
.trackrefresh:hover {
color:#f60;
}
</style>`);
var ordernumbers = [];
document.querySelectorAll('.order-info .first-row .info-body').forEach(el => {
//localStorage.clear();
ordernumbers.push(
gettrack(el, el.textContent.trim())
.then(r => {
return r;
}).catch(e => {
return e;
})
);
});
Promise.all(ordernumbers).then(t => {
t.forEach(e => {
if (e[0] && e[1]) {
insertTrack(e[0], e[1]);
}
});
}, e => {
console.log(e);
});
}
/*
* CHANGELOG
* 1.0   - Первая версия
* 1.0.1 - Добавил поддержку разных валют. Были только доллары.
* 1.1   - Переименовал в AliExpress Improve
*       - Добавил навигацию по категориям (скопировал с низу в верх)
* 1.2   - Исправлена ошибка получения цен: теперь извлекаются цены с отбивкой тысячных пробелом "$1 000" или "1 000 рублей"
* 1.2.1 - Исправлена ошибка получения цен: теперь извлекаются целые цены "$2" или "100 руб."
* 1.2.2 - Исправлена ошибка получения объекта: TypeError: price/shippingPrice is null
* 1.3.0 - Добавлен подсчёт цены за единицу товара, если есть возможность выбирать количество товара
* 1.4.0 - Добавлена ссылка переключения на оригинальный заголовок
* 1.4.1 - Обновлено получение цены доставки. Теперь снова суммируется.
* 1.5.0 - Попытка восстановить дополнительный поиск
* 1.6.0 - Переключение на старый дизайн (переключает не на всех страницах)
* 1.7.0 - Скрытие надоедливой Евы
* 1.8.0 - Отключение aotoplay у карусели при добавление в корзину
* 1.8.1 - Отключение aotoplay у карусели при добавление в избранное
* 1.9.0 - Добавлены номера треков на странице заказов с ссылкой на гдепосылка
* 1.9.1 - Удалён дубль кода
* 1.9.2 - Заменена функция генерации цветов для подсветки консолидированных заказов
* 1.9.3 - Добавлен хак на остановку карусели во время распродаж
* 1.9.4 - Исправлены цвета для консолидированных посылок. Теперь все одинаковые треки одного цвета.
*/