// ==UserScript==
// @name Aliexpress Plus FiZ
// @namespace http://www.zaoios.ru/
// @version 2.5.5
// @description Sorts search results by item price properly with shipping costs included, enhances item pages for Google Chrome
// @author FiZ, Tophness
// @match https://*.aliexpress.com/w/wholesale?*
// @match https://*.aliexpress.com/wholesale?*
// @match https://*.aliexpress.com/af/*
// @match https://*.aliexpress.com/item/*
// @require https://cdnjs.cloudflare.com/ajax/libs/tinysort/2.3.6/tinysort.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/tinysort/2.3.6/tinysort.charorder.min.js
// @license MIT
// @run-at document-idle
// ==/UserScript==
// known bug: after windows resize sometimes need to revert original sort order
var SortTimeoutID;
var CurPageGoods = 0;
var BottomLinksRewritten = false;
var sortmethod = 3;
var showUnitPrice = false;
var elh = {
'sortchange1' : 'Cheapest Unit',
'sortchange2' : 'Cheapest Total',
'sortchange3' : 'Cheapest Total (Max Price)',
'sortchange4' : 'Cheapest',
'sortchange5' : 'Max Price',
};
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if(mutation.type == 'childList'){
for (var j = 0; j < mutation.addedNodes.length; j++) {
//console.log("mutcn: "+ mutation.addedNodes[j].className);
processall(mutation.addedNodes[j].childNodes);
}
}
});
});
function waitForEl(){
var observera = new MutationObserver(function (mutations, me) {
if(document.querySelector("ul.list-items")) {
me.disconnect();
if(document.location.href.indexOf('g=y') == -1){
observer.observe(document.querySelector("ul.list-items"), { childList: true, subtree: true });
}
else{
observer.observe(document.querySelector("ul.list-items"), { childList: true });
}
return;
}
});
observera.observe(document, {
childList: true,
subtree: true
});
}
function CleanPriceText(pricefixed){
pricefixed=pricefixed.replace("US $","");
pricefixed=pricefixed.replace(" руб.","");
//pricefixed=pricefixed.split(" ").join(""); //pricefixed=pricefixed.replaceAll(" ","");
pricefixed=pricefixed.split("\u00a0").join(""); //pricefixed=pricefixed.replaceAll(/\u00a0/g, ""); //.replace("\ ","");
pricefixed=pricefixed.split(",").join("."); //pricefixed=pricefixed.replaceAll(",",".");
return(pricefixed);
}
function process(listitem){
if(!listitem.querySelector)
return(0);
var pricerow = listitem.querySelector('div.item-price-row');
if(!pricerow)
return(0);
if(listitem.querySelector('span.orig-ord'))
return(0);
var price = pricerow.querySelector('.price-current');
var shipping = listitem.querySelector('.shipping-value');
var shippingtext = (shipping)? shipping.innerText : "";
if(!price || listitem.className == "moved")// && listitem.className.indexOf('product-card') == -1 //&& price.innerText.indexOf('$') != -1
return(0);
//var pricefixed = price.innerText.substring(price.innerText.indexOf('$')+1);
var pricefixed = CleanPriceText(price.innerText);
//console.log("pricefixed: "+pricefixed);
var shippingfixed;
if(shippingtext.indexOf('Free Shipping') != -1 || shippingtext == ''){
shippingfixed = "0.00";
}
else{
shippingfixed = CleanPriceText(shippingtext.substring(shippingtext.indexOf(' ')+1));
}
var pricepretext = price.innerText.substring(0, price.innerText.indexOf('$')+1);
var finalcosttext = "", finalmaxcost = "";
var pricesplit;
if(pricefixed.indexOf(' - ') != -1){
pricesplit = pricefixed.split(' - ');
//if(sortmethod == 3){
// finalcosttext = (parseFloat(pricesplit[1]) + parseFloat(shippingfixed)).toFixed(2) + " - " + (parseFloat(pricesplit[0]) + parseFloat(shippingfixed)).toFixed(2);
//}
//else{
finalcosttext = (parseFloat(pricesplit[0]) + parseFloat(shippingfixed)).toFixed(2) + " - " + (parseFloat(pricesplit[1]) + parseFloat(shippingfixed)).toFixed(2);
finalmaxcost =(parseFloat(pricesplit[1]) + parseFloat(shippingfixed)).toFixed(2);
//}
}
else{
finalcosttext = (parseFloat(pricefixed) + parseFloat(shippingfixed)).toFixed(2);
finalmaxcost = finalcosttext;
}
var finalcostpost;
var finalcostpostwhole;
var priceunitparttemp;
var priceunitel = pricerow.querySelector('span.price-unit');
var packagingsale = listitem.querySelector('div.item-price-row.packaging-sale')
if(packagingsale){
priceunitel = packagingsale.querySelector('span.price-unit');
}
if(showUnitPrice && priceunitel){
var priceuniteltext = priceunitel.innerText;
var priceunit = priceuniteltext.substring(0, priceuniteltext.indexOf(' '));
var priceunitposttext = priceuniteltext.substring(priceuniteltext.indexOf(' '));
var finalcostpart;
if(pricefixed.indexOf(' - ') != -1){
if(sortmethod == 3){
finalcostpart = (parseFloat(pricesplit[1]) / parseFloat(priceunit)).toFixed(2);
}
else{
finalcostpart = (parseFloat(pricesplit[0]) / parseFloat(priceunit)).toFixed(2);
}
}
else{
finalcostpart = (finalcosttext / parseFloat(priceunit)).toFixed(2);
}
if(priceunitposttext.indexOf('/') != -1){
var priceunitsplit = priceunitposttext.split('/');
var priceunitpart = priceunitsplit[0];
var priceunitwhole = priceunitsplit[1];
finalcostpostwhole = finalcosttext + " / " + priceunitwhole;
finalcosttext = finalcostpart + " / " + priceunitpart;
priceunitparttemp = priceunitpart;
}
}
var finalcostdiv = document.createElement('div');
finalcostdiv.className = 'item-total-wrap';
var finalcostpretext = document.createElement('span');
finalcostpretext.className = 'total-pretext';
finalcostpretext.innerHTML = "Total: " + pricepretext;
var finalcostspan = document.createElement('span');
finalcostspan.className = 'total-current';
if(finalcostpostwhole){
finalcostspan.innerHTML = finalcostpostwhole;
if(packagingsale){
pricerow.querySelector('span.price-unit').innerHTML = " / " + priceunitparttemp;
}
else{
listitem.querySelector('div.item-price-row.packaging-sale').querySelector('span.price-unit').innerHTML = " / " + priceunitparttemp;
}
price.innerHTML = pricepretext + finalcostpart;
finalcostdiv.appendChild(finalcostpretext);
if(sortmethod == 1){
finalcostspan.className = 'total-posttext';
var finalcostbr = document.createElement('br');
finalcostbr.style.display = "none";
var finalcostspan2 = document.createElement('span');
finalcostspan2.className = 'total-current';
finalcostspan2.innerHTML = finalcosttext;
finalcostspan2.style.display = "none";
finalcostdiv.appendChild(finalcostspan2);
finalcostdiv.appendChild(finalcostbr);
}
finalcostdiv.appendChild(finalcostspan);
}
else{
finalcostspan.innerHTML = finalcosttext;
var finalmaxcostspan = document.createElement('span');
finalmaxcostspan.className = 'total-max';
finalmaxcostspan.innerHTML = finalmaxcost;
finalmaxcostspan.style.display = "none";
var origOrderspan = document.createElement('span');
origOrderspan.className = 'orig-ord';
origOrderspan.innerHTML = CurPageGoods++;
origOrderspan.style.display = "none";
finalcostdiv.appendChild(finalcostpretext);
finalcostdiv.appendChild(finalcostspan);
finalcostdiv.appendChild(finalmaxcostspan);
finalcostdiv.appendChild(origOrderspan);
}
if(shipping && shipping.parentNode.nextSibling.className != finalcostdiv.className){
price.parentNode.parentNode.parentNode.insertBefore(finalcostdiv, shipping.parentNode.nextSibling);
}else
price.parentNode.parentNode.parentNode.insertBefore(finalcostdiv, price.parentNode.parentNode.nextSibling);
PlanToSortall();
}
function processall(list){
for (var i = 0; i < list.length; i++) {
process(list[i]);
}
}
function PlanToSortall(){
if(SortTimeoutID)
clearTimeout(SortTimeoutID);
SortTimeoutID=setTimeout((function(){
sortall(document.querySelectorAll("li.list-item"), sortmethod);
}),100);
}
function sortall(listitems, sortmethod){
//console.log("Sorting");
//return(0);
SortTimeoutID=0;
if(sortmethod == 0){
tinysort(listitems,{selector:'span.orig-ord', natural:true});// Original sort order, //our new span
}else if(sortmethod == 1){
tinysort(listitems,{selector:'span.tsotal-current', natural:true}); //Cheapest Unit',
}
else if(sortmethod == 2){
tinysort(listitems,{selector:'span.total-current', natural:true}); // Cheapest Total', //our new span
}
else if(sortmethod == 3){
tinysort(listitems,{selector:'span.total-max', natural:true}); //'Cheapest Total (Max Price)', //our new span
}
else if(sortmethod == 4){
tinysort(listitems,{selector:'span.price-current', natural:true}); // 'Cheapest', //ali present
}
else if(sortmethod == 5){
tinysort(listitems,{selector:'span.price-current', natural:true, order: 'desc'}); // 'Max Price', //ali present
}
return(0);
}
function SortRows(mode){
if (sortmethod != mode){
if(mode>0){
document.getElementById('sortchange' + sortmethod).setAttribute('style', 'font-weight: regular');
document.getElementById('sortchange' + mode).setAttribute('style', 'font-weight: bold');
sortmethod = mode;
}
}
sortall(document.querySelectorAll("li.list-item"), mode);
fakeScrollDown();
}
function doalilink(){
// console.log("Start Revert sorting");
SortRows(0);
}
function rewriteAliLinks(){
var proplist = document.querySelector('.sort-by-wrapper');
if(proplist && proplist.childNodes.length > 0){
var proplistall = proplist.querySelectorAll('.sort-item');
for (var i = 0; i < proplistall.length; i++) {
proplistall[i].addEventListener('click', function () {doalilink()}, false);
}
}
}
document.body.onscroll = function() {
if(!BottomLinksRewritten)
rewriteAliBottomLinks();
};
function rewriteAliBottomLinks(){
var proplist, i, proplistall;
proplist = document.querySelector('.next-pagination-pages');
if(proplist && proplist.childNodes.length > 0){
BottomLinksRewritten=true;
//console.log("pl ");
proplistall = proplist.querySelectorAll('.next-btn');
for (i = 0; i < proplistall.length; i++) {
//console.log("ib: "+i);
proplistall[i].addEventListener('click', function () {doalilink()}, false);
}
}
}
function insertsearch(){
rewriteAliLinks();
var sortdiv = document.createElement('span');
sortdiv.className = 'sort-item';
var sortspan = document.createElement('span');
sortspan.className = 'sort-item';
var sortspan2 = document.createElement('span');
sortspan2.className = 'sort-item';
var sortspan3 = document.createElement('span');
sortspan3.className = 'sort-item';
var sortspan4 = document.createElement('span');
sortspan4.className = 'sort-item';
var sortspan5 = document.createElement('span');
sortspan5.className = 'sort-item';
var sortchange = document.createElement('span');
sortchange.id = 'sortchange1';
sortchange.innerHTML = elh[sortchange.id];
sortchange.addEventListener("click", function () {
SortRows(1) //'Cheapest Unit',
}, false);
var sortchange2 = document.createElement('span');
sortchange2.id = 'sortchange2';
sortchange2.innerHTML = elh[sortchange2.id];
sortchange2.addEventListener("click", function () {
SortRows(2) // 'Cheapest Total',
}, false);
var sortchange3 = document.createElement('span');
sortchange3.id = 'sortchange3';
sortchange3.innerHTML = elh[sortchange3.id];
sortchange3.addEventListener("click", function () {
SortRows(3) //'Cheapest Total (Max Price)',
}, false);
var sortchange4 = document.createElement('span');
sortchange4.id = 'sortchange4';
sortchange4.innerHTML = elh[sortchange4.id];
sortchange4.addEventListener("click", function () {
SortRows(4) //'Cheapest',
}, false);
var sortchange5 = document.createElement('label');
sortchange5.id = 'sortchange5';
sortchange5.innerHTML = elh[sortchange5.id] + ': ';
var sortchange5t = document.createElement('input');
sortchange5t.id = 'sortchange5t';
sortchange5t.addEventListener("keydown", function () {
SortRows(5) //'Max Price',
}, false);
sortspan.appendChild(sortchange);
sortspan2.appendChild(sortchange2);
sortspan3.appendChild(sortchange3);
sortspan4.appendChild(sortchange4);
sortspan5.appendChild(sortchange5);
sortspan5.appendChild(sortchange5t);
sortdiv.appendChild(sortspan);
sortdiv.appendChild(sortspan2);
sortdiv.appendChild(sortspan3);
sortdiv.appendChild(sortspan4);
sortdiv.appendChild(sortspan5);
var searchbox = document.querySelector(".sort-by-wrapper");
if(searchbox){
// searchbox.appendChild(sortdiv);
searchbox.appendChild(sortspan);
searchbox.appendChild(sortspan2);
searchbox.appendChild(sortspan3);
searchbox.appendChild(sortspan4);
searchbox.appendChild(sortspan5);
if(sortmethod>0)
document.getElementById('sortchange' + sortmethod).setAttribute('style', 'font-weight: bold');
}
}
function process2(item){
if(item.className == "item-info"){
if(item.querySelector("div.item-title.line-limit-length")){
item.querySelector("div.item-title.line-limit-length").classList.remove('line-limit-length');
//item.parentNode.parentNode.style.marginBottom = "88px";
item.parentNode.parentNode.style.height = "auto";
}
}
}
function checkall(list){
for (var i = 0; i < list.length; i++) {
process2(list[i]);
}
}
var observer2 = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if(mutation.type == 'childList'){
for (var j = 0; j < mutation.addedNodes.length; j++) {
checkall(mutation.addedNodes[j].childNodes);
}
}
});
});
function waitForEl2(){
var observerb = new MutationObserver(function (mutations, me) {
if(document.querySelector(".item-title-block")) {
me.disconnect();
observer2.observe(document.querySelector(".bottom-recommendation"), { childList: true, subtree: true });
return;
}
});
observerb.observe(document, {
childList: true,
subtree: true
});
}
function fakeScrollDown(){
window.scrollBy(0, window.innerHeight);
setTimeout((function(){
//window.scrollByPages(1);;
//window.scrollBy(0, window.innerHeight);;
// console.log("height: "+(window.scrollY+ window.innerHeight) +"from "+ document.body.scrollHeight + "wh "+ window.innerHeight);
if((window.scrollY+ window.innerHeight) < document.body.scrollHeight){ //window.scrollMaxY
fakeScrollDown();
}
else{
window.scrollTo(0,0);
}
}),100);
}
function docalctotal(){
var itempageshipping = document.querySelector('.product-shipping-price');
if(itempageshipping){
itempageshipping = itempageshipping.innerText;
if(itempageshipping.indexOf('Free Shipping') != -1){
itempageshipping = '0.00';
}
itempageshipping = itempageshipping.substring(itempageshipping.indexOf(':')+2);
itempageshipping = parseFloat(CleanPriceText(itempageshipping)); //itempageshipping = parseFloat(itempageshipping.substring(itempageshipping.indexOf('$')+1).trimEnd());
var itempageprice = document.querySelector('.product-price-value');
if(itempageprice){
itempageprice = itempageprice.innerText;
var preprice = itempageprice.substring(itempageprice.indexOf(':')+1, itempageprice.indexOf('$')+1);
//itempageprice = parseFloat(itempageprice.substring(itempageprice.indexOf('$')+1).trimEnd());
itempageprice = parseFloat(CleanPriceText(itempageprice));
var itempagetotal = parseFloat(itempageshipping + itempageprice).toFixed(2).toString();
var finalcostpretext = document.createElement('span');
finalcostpretext.className = 'total-pretext';
finalcostpretext.innerHTML = "Total: " + preprice + itempagetotal;
finalcostpretext.style.fontSize = "24px";
finalcostpretext.style.fontWeight = "700";
var finalcostdiv = document.createElement('div');
finalcostdiv.className = 'total-current';
finalcostdiv.appendChild(finalcostpretext);
var insertitemtotal = document.querySelector('.product-action');
if(insertitemtotal){
var pretextitem = document.querySelector('.total-pretext');
if(pretextitem){
pretextitem.innerHTML = "Total: " + preprice + itempagetotal;
}
else{
insertitemtotal.parentNode.insertBefore(finalcostdiv, insertitemtotal);
}
}
}
}
}
function calctotal(){
var proplist = document.querySelector('.sku-wrap');
if(proplist && proplist.childNodes.length > 0){
var proplistall = proplist.querySelectorAll('.sku-property');
for (var i = 0; i < proplistall.length; i++) {
var propitem = proplistall[i].querySelectorAll('.sku-property-item');
if(!propitem[0].classList.contains('selected')){
propitem[0].click();
}
for (var i2 = 0; i2 < propitem.length; i2++) {
propitem[i2].addEventListener('click', function() {
setTimeout((function(){
docalctotal();
}),1000);
});
}
}
setTimeout((function(){
docalctotal();
}),1000);
}
else{
docalctotal();
}
}
if(document.location.href.indexOf('/wholesale') != -1 || document.location.href.indexOf('/af') != -1){
waitForEl();
processall(document.querySelectorAll("li.list-item"));
//sortall(document.querySelectorAll("li.list-item"));
insertsearch();
fakeScrollDown();
}
else if(document.location.href.indexOf('/item') != -1){
waitForEl2();
setTimeout((function(){
checkall(document.querySelectorAll(".item-info"));
calctotal();
}),2000);
}