Last active
January 6, 2021 18:33
-
-
Save theseanl/95d91f7efc361b8b80b672b06c810904 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 Coupang price trends | |
// @namespace seanl | |
// @description Attaches buttons that links to price trends page on coupang websites | |
// @version 1.0.1 | |
// @license MIT | |
// @match https://www.coupang.com/* | |
// @grant unsafeWindow | |
// @run-at document-end | |
// ==/UserScript== | |
const processed = new WeakSet(); | |
const ANCHOR_CLASS = 'trend__anchor'; | |
const searchPageStyle = `a.${ANCHOR_CLASS} { position: absolute; bottom: 10px; right: 10px; }`; | |
const productPageStyle = `a.${ANCHOR_CLASS} { vertical-align: bottom; }`; | |
function linkTemplate(href) { | |
return `<a class="${ANCHOR_CLASS}" href="${href}" target="_blank" style="vertical-align:bottom"><img width=20 height=20 src="http://alltimeprice.com/favicon.ico"></img></a>` | |
} | |
let hasStyle = false; | |
function ensureStyleAdded(css) { | |
if (hasStyle) return; | |
const style = document.createElement('style'); | |
style.textContent = css; | |
document.body.appendChild(style); | |
hasStyle = true; | |
} | |
//function insertLink(el, href) { | |
function insertLink(el, pid, itemId) { | |
if (processed.has(el)) return; | |
processElement(el, pid, itemId); | |
processed.add(el); | |
} | |
function processElement(el, pid, itemId) { | |
el.insertAdjacentHTML('beforeend', linkTemplate(`https://alltimeprice.com/product/?pid=${pid}-${itemId}`)); | |
} | |
const reProductId = /^\/vp\/products\/([\d]*)$/ | |
function onProductLink(anchor) { | |
let rocketBadge = anchor.getElementsByClassName("rocket badge"); | |
if (rocketBadge === null || rocketBadge.length === 0) return; | |
const {href} = anchor; | |
const url = new URL(href); | |
let match = reProductId.exec(url.pathname); | |
if (match === null) return; | |
const pid = match[1]; | |
const itemId = url.searchParams.get("vendorItemId"); | |
ensureStyleAdded(searchPageStyle); | |
insertLink(anchor, pid, itemId); | |
} | |
function findProductLinkSubtree(node) { | |
if (node.tagName === "A" && node.href.startsWith("/vp/products")) { | |
onProductLink(node); | |
} else { | |
let anchors = node.querySelectorAll("a[href^='/vp/products/"); | |
if (!anchors) return; | |
for (let anchor of anchors) { | |
onProductLink(anchor); | |
} | |
} | |
} | |
function onSalePrice(div) { | |
const pid = unsafeWindow["sdp"]["productId"]; | |
const itemId = unsafeWindow["sdp"]["vendorItemId"] | |
if (!pid || !itemId) return; | |
ensureStyleAdded(productPageStyle); | |
insertLink(div, pid, itemId); | |
} | |
function findSalePriceSubtree(node) { | |
if (node.classList.contains("prod-sale-price")) { | |
onSalePrice(node); | |
} else { | |
let nodes = node.getElementsByClassName("prod-sale-price"); | |
if (!nodes) return; | |
for (let node of nodes) { | |
onSalePrice(node); | |
} | |
} | |
} | |
function findElements(finder) { | |
finder(document.documentElement); | |
new MutationObserver((mutations) => { | |
for (let mutation of mutations) { | |
let { addedNodes } = mutation; | |
if (!addedNodes) continue; | |
for (let addedNode of addedNodes) { | |
if (addedNode.nodeType !== Node.ELEMENT_NODE) continue; | |
finder(addedNode); | |
} | |
} | |
}).observe(document.documentElement, { | |
subtree: true, | |
childList: true | |
}); | |
} | |
if (location.pathname.startsWith("/np/search")) { | |
findElements(findProductLinkSubtree); | |
} else if (location.pathname.startsWith("/vp/products/")) { | |
findElements(findSalePriceSubtree); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment