You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
5.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* 方案 A页面加载时注入保留双地址 React 状态,阻止 pickup 在切换 delivery 时被清空。
* 纯字符串,供 context.addInitScript 使用。
*/
export const DUAL_ADDRESS_PATCH_INIT = `(() => {
if (window.__rpaDualAddressPatchInstalled) return;
window.__rpaDualAddressPatchInstalled = true;
window.__rpaDualAddressVault = { pickup: null, delivery: null };
function findQuoterStateNode() {
var selectors = [
"#react-quoter-landing-plugin",
"[data-testid='quoter-widget']",
"[class*='Quoter']",
];
var widget = null;
for (var s = 0; s < selectors.length; s += 1) {
widget = document.querySelector(selectors[s]);
if (widget) break;
}
if (!widget) return null;
var fiberKey = Object.keys(widget).find(function(k) {
return k.indexOf("__reactFiber$") === 0 || k.indexOf("__reactInternalInstance$") === 0;
});
if (!fiberKey) return null;
var queue = [widget[fiberKey]];
var seen = new Set();
while (queue.length > 0) {
var fiber = queue.shift();
if (!fiber || seen.has(fiber)) continue;
seen.add(fiber);
var sn = fiber.stateNode;
if (sn && typeof sn.setState === "function" && sn.state) {
var st = sn.state;
if (
"pickupAddress" in st ||
"pickup" in st ||
"deliveryAddress" in st ||
(st.addresses && typeof st.addresses === "object")
) {
return sn;
}
}
if (fiber.child) queue.push(fiber.child);
if (fiber.sibling) queue.push(fiber.sibling);
}
return null;
}
function buildAddressData(entry) {
if (!entry) return null;
return {
placeId: entry.placeId,
location: entry.location || {},
formattedAddress: entry.description || entry.formattedAddress || "",
isCommitted: true,
};
}
function isPickupCleared(partial, prevState) {
if (!partial || typeof partial !== "object") return false;
var keys = ["pickupAddress", "pickup"];
for (var i = 0; i < keys.length; i += 1) {
var k = keys[i];
if (!(k in partial)) continue;
var v = partial[k];
if (v === null || v === undefined || v === "") return true;
if (typeof v === "object" && !v.placeId && !v.formattedAddress) return true;
}
if (partial.addresses && partial.addresses.pickup === null) return true;
if (
partial.activeAddressSide === "delivery" &&
prevState &&
prevState.pickupAddress &&
!partial.pickupAddress
) {
return true;
}
return false;
}
function wrapStateNode(node) {
if (!node || node.__rpaDualPatchWrapped) return;
node.__rpaDualPatchWrapped = true;
var orig = node.setState.bind(node);
node.setState = function(partial, callback) {
var vault = window.__rpaDualAddressVault;
if (vault && vault.pickup && isPickupCleared(partial, node.state)) {
var pdata = buildAddressData(vault.pickup);
if (pdata) {
partial = Object.assign({}, partial, { pickupAddress: pdata });
}
}
if (vault && vault.delivery && partial && partial.deliveryAddress === null) {
var ddata = buildAddressData(vault.delivery);
if (ddata) {
partial = Object.assign({}, partial, { deliveryAddress: ddata });
}
}
return orig(partial, callback);
};
}
function injectSide(side) {
var entry = window.__rpaDualAddressVault[side];
if (!entry) return false;
var node = findQuoterStateNode();
if (!node) return false;
wrapStateNode(node);
var data = buildAddressData(entry);
if (!data) return false;
var patch = {};
if (side === "pickup") {
patch.pickupAddress = data;
patch.activeAddressSide = "delivery";
} else {
patch.deliveryAddress = data;
}
try {
node.setState(patch);
return true;
} catch (e) {
return false;
}
}
window.__rpaDualAddressApi = {
register: function(side, payload) {
window.__rpaDualAddressVault[side] = payload;
var node = findQuoterStateNode();
if (node) wrapStateNode(node);
return injectSide(side);
},
preservePickup: function() {
var node = findQuoterStateNode();
if (node) wrapStateNode(node);
return injectSide("pickup");
},
preserveBoth: function() {
var pickupOk = injectSide("pickup");
var deliveryOk = injectSide("delivery");
return pickupOk && deliveryOk;
},
hasPickup: function() {
var v = window.__rpaDualAddressVault.pickup;
return !!(v && v.placeId);
},
stats: function() {
return {
pickupRegistered: !!window.__rpaDualAddressVault.pickup,
deliveryRegistered: !!window.__rpaDualAddressVault.delivery,
wrapped: !!findQuoterStateNode(),
apiInstalled: true,
};
},
releasePickupInput: function() {
var widget = document.querySelector("#react-quoter-landing-plugin");
if (!widget) return false;
var clicked = false;
var nodes = widget.querySelectorAll("*");
for (var i = 0; i < nodes.length; i += 1) {
var t = (nodes[i].textContent || "").trim();
if (/^(Deliver to|Delivery to|Where to\?)$/i.test(t)) {
nodes[i].click();
clicked = true;
break;
}
}
var inputs = widget.querySelectorAll("input");
for (var j = 0; j < inputs.length; j += 1) {
var ph = (inputs[j].placeholder || "").toLowerCase();
if (!/search/.test(ph)) continue;
if ((inputs[j].value || "").trim().length >= 8) {
inputs[j].blur();
}
}
return clicked;
},
};
var tick = 0;
setInterval(function() {
if (!window.__rpaDualAddressVault.pickup) return;
tick += 1;
if (tick % 4 !== 0) return;
var node = findQuoterStateNode();
if (node) {
wrapStateNode(node);
injectSide("pickup");
}
}, 400);
})();`;