Last active
February 13, 2020 13:44
-
-
Save FelixWolf/6809d7850917e3470dcd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name SL Marketplace Extender | |
// @namespace http://tools.softhyena.com | |
// @updateURL https://gist.githubusercontent.com/FelixWolf/6809d7850917e3470dcd/raw/ | |
// @downloadURL https://gist.githubusercontent.com/FelixWolf/6809d7850917e3470dcd/raw/ | |
// @version 0.3 | |
// @description Adds features to the marketplace which should be there | |
// @author Chaser Zaks | |
// @match https://marketplace.secondlife.com/* | |
// @grant GM_xmlhttpRequest | |
// @grant GM_getValue | |
// @grant GM_setValue | |
// ==/UserScript== | |
//LIBRARY FUNCTIONS | |
var pageHandlers = {}; | |
function addPageController(n, c, e) { | |
pageHandlers[n] = { | |
"Condition": c, | |
"Event": e | |
}; | |
} | |
function escapeHtml(a) { | |
return a.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"); | |
} | |
function randStr(len) { | |
var r = ""; | |
for (var i = 0; i < len; i++) { | |
var chr = Math.round(Math.random() * 50); | |
if (chr > 25) chr = chr + 6; | |
r = r + String.fromCharCode(65 + chr); | |
} | |
return r; | |
} | |
//END LIBRARY FUNCTIONS | |
//Product page: | |
addPageController("keywords", function(l) { | |
return l.substring(0, 3) == "/p/"; | |
}, function() { | |
console.log("Keywords executed"); | |
//Add keywords | |
var elm = document.getElementById("product-details"); | |
if (elm !== null) { | |
var addInfo = document.createElement("li"); | |
var keywords = document.head.querySelector("meta[name=keywords]"); | |
if (keywords !== null) { | |
var tmp = keywords.content.split(/,\s?/g); | |
keywords = "<i>"; | |
for (var i = 0, l = tmp.length - 2; i < tmp.length; i++) { | |
keywords += "<a href=\"https://marketplace.secondlife.com/products/search?utf8=%E2%9C%93&search%5Bcategory_id%5D=&search%5Bmaturity_level%5D=GMA&search%5Bkeywords%5D=" + escape(tmp[i]) + "\">" + escapeHtml(tmp[i]) + "</a>" + (i > l ? "" : ", "); | |
} | |
keywords += "</i>"; | |
} else | |
keywords = "<i>None</i>"; | |
addInfo.style.wordWrap = "break-word"; | |
addInfo.innerHTML = "<B>Tags:</B><br/>" + keywords + "<br/>"; | |
elm.children[0].appendChild(addInfo); | |
} | |
}); | |
//Redeliver button: | |
addPageController("redeliver", function(l) { | |
return l.substring(0, 3) == "/p/"; | |
}, function() { | |
console.log("Keywords executed"); | |
//Add keywords | |
function getOrdersPageUrl(){ | |
var notices = document.querySelectorAll("#flash_notice a"); | |
for(var notice of notices){ | |
if(notice.href.indexOf("/orders/") !== -1 || notice.href.indexOf("/gifts/") !== -1) | |
return notice.href; | |
} | |
return null; | |
} | |
function getRedeliveryUrl(url, pid, callback){ | |
var xhr = new XMLHttpRequest(); | |
xhr.open("GET", url, true); | |
xhr.onload = function() { | |
var parser = new DOMParser(), | |
doc = parser.parseFromString(xhr.responseText, "text/html"); | |
if(url.indexOf("/orders/") !== -1){ | |
var elms = doc.querySelectorAll("#order #shopping-cart .line-item-row"); | |
for(var found of elms){ | |
if(found.querySelector(".line-item-gift").children.length == 0){ | |
if(found.querySelector("h4 a").href.split("/").pop() == pid){ | |
var links = found.querySelectorAll("a"); | |
for(var link of links){ | |
if(link.href.indexOf("/redeliver") !== -1){ | |
callback(link.href); | |
return; | |
} | |
} | |
} | |
} | |
} | |
}else if(url.indexOf("/gifts/") !== -1){ | |
var elms = doc.querySelectorAll("#order #gifts"); | |
for(var found of elms){ | |
if(found.querySelector("h4 a").href.split("/").pop() == pid){ | |
var links = found.querySelectorAll("a"); | |
for(var link of links){ | |
if(link.href.indexOf("/redeliver") !== -1){ | |
callback(link.href); | |
return; | |
} | |
} | |
} | |
} | |
} | |
callback(null); | |
}; | |
xhr.send(null); | |
} | |
function executeRedelivery(url, callback){ | |
var token_name = document.head.querySelector('meta[name="csrf-param"]'), | |
token_value = document.head.querySelector('meta[name="csrf-token"]'); | |
var xhr = new XMLHttpRequest(); | |
xhr.open("POST", url, true); | |
xhr.onload = function() { | |
callback(null); | |
}; | |
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); | |
xhr.send("_method=post&"+encodeURIComponent(token_name.content)+"="+encodeURIComponent(token_value.content)); | |
} | |
function isRedeliverable(){ | |
var poos = document.body.querySelectorAll(".cmt"); | |
for(var poo of poos){ | |
if(poo.textContent == "Copy"){ | |
for(var cls of poo.classList) | |
if(cls == "permitted") | |
return true; | |
} | |
} | |
return false; | |
} | |
var redeliverUrl = getOrdersPageUrl(); | |
if(redeliverUrl !== null && isRedeliverable()){ | |
var btn = document.createElement("button"); | |
btn.setAttribute("class", "button cart-button"); | |
btn.style.backgroundImage = "linear-gradient(#00b7ea,#009ec3)"; | |
btn.textContent = "Redeliver"; | |
btn.addEventListener("click", function(){ | |
btn.textContent = "Working..."; | |
btn.setAttribute("disabled", "disabled"); | |
getRedeliveryUrl(redeliverUrl, document.location.pathname.split("/").pop(), function(url){ | |
executeRedelivery(url, function(){ | |
btn.textContent = "Redeliver"; | |
btn.removeAttribute("disabled"); | |
}); | |
}); | |
}); | |
document.getElementById("add-to-cart-form").appendChild(btn); | |
} | |
//getRedeliveryUrl(getOrdersPageUrl(), 15237316, function(a){executeRedelivery(a);}); | |
}); | |
//Add clickable reviewer names | |
addPageController("reviewerNames", function(l) { | |
return l.substring(0, 3) == "/p/"; | |
}, function() { | |
//Fix reviewer names | |
var rnf = document.getElementsByClassName("review-author"); | |
for (var i = 0; i < rnf.length; i++) { | |
var tmp = rnf[i].getElementsByTagName("a")[0]; | |
tmp.setAttribute("href", "https://my.secondlife.com/" + (tmp.innerText.replace(/\s/g, "."))); | |
} | |
var rnf = document.getElementsByClassName("comment-author"); | |
for (var i = 0; i < rnf.length; i++) { | |
var tmp = rnf[i].getElementsByTagName("strong")[0]; | |
var who = tmp.innerText, | |
lnk = document.createElement("a"); | |
tmp.innerText = ""; | |
lnk.innerText = who; | |
lnk.setAttribute("href", "https://my.secondlife.com/" + (who.replace(/\s/g, "."))); | |
tmp.appendChild(lnk); | |
} | |
}); | |
//Add search parameters | |
addPageController("searchParams", function(l) { | |
return true; | |
}, function() { | |
var srch = document.getElementById("new_search"); | |
function addParameter(name, label, options) { | |
var p = document.createElement("p"), | |
rnd = randStr(16), | |
lab = document.createElement("label"), | |
el = null; | |
if (typeof(options) == "undefined") { | |
el = document.createElement("input"); | |
el.setAttribute("size", 30); | |
el.setAttribute("text", "text"); | |
} else if (typeof(options) == "object") { | |
el = document.createElement("select"); | |
if (Array.isArray(options)) { | |
for (var i = 0; i < options.length; i++) { | |
var tmp = document.createElement("option"); | |
tmp.setAttribute("value", options[i]); | |
tmp.innerText = options[i]; | |
el.appendChild(tmp); | |
} | |
} else { | |
for (var i = 0, x = Object.keys(options); i < x.length; i++) { | |
var tmp = document.createElement("option"); | |
tmp.setAttribute("value", x[i]); | |
tmp.innerText = options[x[i]]; | |
el.appendChild(tmp); | |
} | |
} | |
} | |
lab.innerText = label; | |
lab.setAttribute("for", rnd); | |
p.appendChild(lab); | |
el.setAttribute("name", name); | |
el.setAttribute("id", rnd); | |
p.appendChild(el); | |
srch.appendChild(p); | |
} | |
srch.appendChild(document.createElement("br")); | |
addParameter("search[sort]", "Sort by", { | |
"sales_rank_asc": "Best Selling", | |
"relevance_desc": "Relevance", | |
"created_at_desc": "Age: Newest First", | |
"created_at_asc": "Age: Oldest First", | |
"price_asc": "Price: Low to High", | |
"price_desc": "Price: High to Low", | |
"name_asc": "Name: A to Z", | |
"name_desc": "Name: Z to A", | |
"prim_count_asc": "Prims: Low to High", | |
"prim_count_desc": "Prims: High to Low", | |
"average_rating_desc": "Rating: High to Low" | |
}); | |
addParameter("search[per_page]", "Results", [96, 48, 24, 12, 8, 4, 2]); | |
//Permission based search | |
var perms = document.createElement("p"); | |
//Copy | |
var tmp = document.createElement("input"), | |
tmpn = randStr(16); | |
tmp.setAttribute("type", "checkbox"); | |
tmp.setAttribute("id", tmpn); | |
tmp.style.clear = "initial"; | |
tmp.setAttribute("name", "search[copy_permission]"); | |
perms.appendChild(tmp); | |
var tmp = document.createElement("label"); | |
tmp.setAttribute("for", tmpn); | |
tmp.style.clear = "initial"; | |
tmp.innerText = "\xa0Copy\xa0\xa0"; | |
perms.appendChild(tmp); | |
//Modify | |
var tmp = document.createElement("input"), | |
tmpn = randStr(16); | |
tmp.setAttribute("type", "checkbox"); | |
tmp.setAttribute("id", tmpn); | |
tmp.style.clear = "initial"; | |
tmp.setAttribute("name", "search[modify_permission]"); | |
perms.appendChild(tmp); | |
var tmp = document.createElement("label"); | |
tmp.setAttribute("for", tmpn); | |
tmp.innerText = "\xa0Modify\xa0\xa0"; | |
tmp.style.clear = "initial"; | |
perms.appendChild(tmp); | |
//Transfer | |
var tmp = document.createElement("input"), | |
tmpn = randStr(16); | |
tmp.setAttribute("type", "checkbox"); | |
tmp.setAttribute("id", tmpn); | |
tmp.style.clear = "initial"; | |
tmp.setAttribute("name", "search[transfer_permission]"); | |
perms.appendChild(tmp); | |
var tmp = document.createElement("label"); | |
tmp.setAttribute("for", tmpn); | |
tmp.style.clear = "initial"; | |
tmp.innerText = "\xa0Transfer"; | |
perms.appendChild(tmp); | |
//Price sorting | |
perms.appendChild(document.createElement("br")); | |
var tmp = document.createElement("input"); | |
tmp.setAttribute("type", "number"); | |
tmp.setAttribute("name", "search[price_low]"); | |
tmp.style.clear = "initial"; | |
tmp.style.width = "55px"; | |
tmp.style.height = "18px"; | |
tmp.style.padding = "0 2px"; | |
perms.appendChild(tmp); | |
var tmp = document.createElement("label"); | |
tmp.style.clear = "initial"; | |
tmp.innerText = "\xa0to\xa0"; | |
perms.appendChild(tmp); | |
var tmp = document.createElement("input"); | |
tmp.setAttribute("type", "number"); | |
tmp.setAttribute("name", "search[price_high]"); | |
tmp.style.clear = "initial"; | |
tmp.style.width = "55px"; | |
tmp.style.height = "18px"; | |
tmp.style.padding = "0 2px"; | |
perms.appendChild(tmp); | |
srch.appendChild(perms); | |
}); | |
//Auto continue | |
addPageController("skipContinue", function(l) { | |
return l == "/orders/checkout/continue"; | |
}, function() { | |
document.getElementsByClassName("button-to")[0].submit(); | |
}); | |
//Auto continue | |
addPageController("removeAds", function(l) { | |
return true; | |
}, function() { | |
var elms = document.getElementsByClassName("advertisement"); | |
//Removing a element by .remove() apparently removes it from the array as well | |
//Work around: loop while elms.length is greater than 0 and remove entry [0] | |
while (elms.length > 0) { | |
elms[0].remove(); | |
} | |
}); | |
//Infinite scroll | |
addPageController("infiniteScroll", function(l) { | |
var tmp = document.location.pathname.substring(1).split("/"); | |
if (tmp.pop() == "search") { | |
return true; | |
} | |
return false; | |
}, function() { | |
function getProducts(page, callback) { | |
var xhr = new XMLHttpRequest(); | |
xhr.open("GET", document.location.href + "&search%5Bpage%5D=" + page, true); | |
xhr.onreadystatechange = function() { | |
if (xhr.readyState == 4 && xhr.status == 200) { | |
var parser = new DOMParser(), | |
doc = parser.parseFromString(xhr.responseText, "text/html"); | |
callback(doc.querySelectorAll(".product-listing")[0].children); | |
} | |
}; | |
xhr.send(null); | |
} | |
function getPageCount() { | |
var pagination = document.querySelectorAll(".pagination")[0].children; | |
if (pagination.length > 2) { | |
return parseInt(pagination[pagination.length - 2].innerText); | |
} | |
return 1; | |
} | |
function parseQS(input) { | |
if (typeof(input) == "undefined") { | |
input = document.location.search.substring(1).split("&"); | |
} else { | |
if (input.charAt(0) == "?") | |
input = input.substring(1); | |
input = input.split("&"); | |
} | |
var output = {}; | |
for (var i = 0; i < input.length; i++) { | |
var tmp = input[i].indexOf("="); | |
output[decodeURIComponent(input[i].substring(0, tmp))] = decodeURIComponent(input[i].substring(tmp + 1)); | |
} | |
return output; | |
} | |
function getCurrentPage() { | |
var qs = parseQS(); | |
if (typeof(qs["search[page]"]) != "undefined") { | |
return parseInt(qs["search[page]"]); | |
} | |
return 1; | |
} | |
function appendElements(src, dst) { | |
for (var i = 0; i < src.length; i++) { | |
dst.appendChild(src[i]); | |
} | |
} | |
var currentPage = getCurrentPage(), | |
totalPages = getPageCount(), | |
listings = document.querySelectorAll(".product-listing")[0], | |
paginationFooter = document.querySelectorAll(".footer-paginate")[0], | |
isLoadingNewPage = false; | |
paginationFooter.innerText = "Working..."; | |
document.addEventListener('scroll', function(event) { | |
if (isLoadingNewPage) | |
return; | |
if (document.body.scrollHeight <= window.scrollY + window.innerHeight + 32) { | |
if (currentPage < totalPages) { | |
isLoadingNewPage = true; | |
paginationFooter.innerText = "Loading page " + (currentPage + 1) + "..."; | |
getProducts(++currentPage, function(els) { | |
appendElements(els, listings); | |
isLoadingNewPage = false; | |
paginationFooter.innerText = "Working..."; | |
}); | |
} else if (currentPage == totalPages) { | |
//Handle end of page | |
paginationFooter.innerText = "End of results."; | |
currentPage++; | |
} | |
} | |
}); | |
}); | |
//Initializer | |
function main() { | |
var path = location.pathname; | |
for (var i = 0, x = Object.keys(pageHandlers), l = x.length; i < l; i++) { | |
if (pageHandlers[x[i]].Condition(path)) | |
pageHandlers[x[i]].Event(); | |
} | |
} | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment