mirror of
https://ghfast.top/https://github.com/StarCitizenToolBox/StarCitizenBoxBrowserEx.git
synced 2025-05-09 21:51:25 +08:00
typescript support
This commit is contained in:
parent
3c5d7f0797
commit
13e0e78e48
4
.gitignore
vendored
4
.gitignore
vendored
@ -9,6 +9,8 @@ node_modules
|
||||
# testing
|
||||
coverage
|
||||
|
||||
# dist/
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
||||
@ -25,3 +27,5 @@ yarn-error.log*
|
||||
|
||||
# extension.js
|
||||
extension-env.d.ts
|
||||
|
||||
.vscode/
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -3,7 +3,9 @@
|
||||
"clazz",
|
||||
"erkul",
|
||||
"robertsspaceindustries",
|
||||
"SWTT",
|
||||
"timeago",
|
||||
"uexcorp",
|
||||
"WARBOND"
|
||||
]
|
||||
}
|
@ -1,166 +0,0 @@
|
||||
let dataVersion = null
|
||||
|
||||
chrome.runtime.onInstalled.addListener(function () {
|
||||
_checkVersion().then(_ => {
|
||||
});
|
||||
console.log("SWTT init");
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
||||
if (request.action === "_loadLocalizationData") {
|
||||
_initLocalization(request.url).then(data => {
|
||||
sendResponse({result: data});
|
||||
});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
async function _checkVersion() {
|
||||
dataVersion = await _getJsonData("versions.json");
|
||||
console.log("Localization Version ===");
|
||||
console.log(dataVersion);
|
||||
}
|
||||
|
||||
async function _initLocalization(url) {
|
||||
console.log("url ===" + url);
|
||||
if (dataVersion == null) {
|
||||
await _checkVersion();
|
||||
return _initLocalization(url);
|
||||
}
|
||||
let v = dataVersion
|
||||
// TODO check version
|
||||
let data = {};
|
||||
|
||||
if (url.includes("robertsspaceindustries.com") || url.includes("manual")) {
|
||||
data["zh-CN"] = await _getJsonData("zh-CN-rsi.json", {cacheKey: "zh-CN", version: v.rsi});
|
||||
data["concierge"] = await _getJsonData("concierge.json", {cacheKey: "concierge", version: v.concierge});
|
||||
data["orgs"] = await _getJsonData("orgs.json", v.orgs);
|
||||
data["address"] = await _getJsonData("addresses.json", {cacheKey: "orgs", version: v.addresses});
|
||||
data["hangar"] = await _getJsonData("hangar.json", {cacheKey: "hangar", version: v.hangar});
|
||||
} else if (url.includes("uexcorp.space")) {
|
||||
data["UEX"] = await _getJsonData("zh-CN-uex.json", {cacheKey: "uex", version: v.uex});
|
||||
} else if (url.includes("erkul.games")) {
|
||||
data["DPS"] = await _getJsonData("zh-CN-dps.json", {cacheKey: "dps", version: v.dps});
|
||||
}
|
||||
// update data
|
||||
let replaceWords = [];
|
||||
|
||||
function addLocalizationResource(key) {
|
||||
replaceWords.push(...getLocalizationResource(data, key));
|
||||
}
|
||||
|
||||
if (url.includes("robertsspaceindustries.com") || url.includes("manual")) {
|
||||
const org = "https://robertsspaceindustries.com/orgs";
|
||||
const citizens = "https://robertsspaceindustries.com/citizens";
|
||||
const organization = "https://robertsspaceindustries.com/account/organization";
|
||||
const concierge = "https://robertsspaceindustries.com/account/concierge";
|
||||
const referral = "https://robertsspaceindustries.com/account/referral-program";
|
||||
const address = "https://robertsspaceindustries.com/account/addresses";
|
||||
const hangar = "https://robertsspaceindustries.com/account/pledges";
|
||||
const spectrum = "https://robertsspaceindustries.com/spectrum/community/";
|
||||
if (url.startsWith(spectrum)) {
|
||||
return;
|
||||
}
|
||||
addLocalizationResource("zh-CN");
|
||||
if (url.startsWith(org) || url.startsWith(citizens) || url.startsWith(organization)) {
|
||||
replaceWords.push({"word": 'members', "replacement": '名成员'});
|
||||
addLocalizationResource("orgs");
|
||||
}
|
||||
if (url.startsWith(address)) {
|
||||
addLocalizationResource("address");
|
||||
}
|
||||
|
||||
if (url.startsWith(referral)) {
|
||||
replaceWords.push(
|
||||
{"word": 'Total recruits: ', "replacement": '总邀请数:'},
|
||||
{"word": 'Prospects ', "replacement": '未完成的邀请'},
|
||||
{"word": 'Recruits', "replacement": '已完成的邀请'}
|
||||
);
|
||||
}
|
||||
|
||||
if (url.startsWith(concierge)) {
|
||||
replaceWords = [];
|
||||
addLocalizationResource("concierge");
|
||||
}
|
||||
|
||||
if (url.startsWith(hangar)) {
|
||||
addLocalizationResource("hangar");
|
||||
}
|
||||
} else if (url.includes("uexcorp.space")) {
|
||||
addLocalizationResource("UEX");
|
||||
} else if (url.includes("erkul.games")) {
|
||||
addLocalizationResource("DPS");
|
||||
}
|
||||
return replaceWords;
|
||||
}
|
||||
|
||||
|
||||
function getLocalizationResource(localizationResource, key) {
|
||||
const localizations = [];
|
||||
const dict = localizationResource[key];
|
||||
if (typeof dict === "object") {
|
||||
for (const [k, v] of Object.entries(dict)) {
|
||||
const trimmedKey = k
|
||||
.toString()
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/\xa0/g, ' ')
|
||||
.replace(/\s{2,}/g, ' ');
|
||||
localizations.push({"word": trimmedKey, "replacement": v.toString()});
|
||||
}
|
||||
}
|
||||
return localizations;
|
||||
}
|
||||
|
||||
async function _getJsonData(fileName, {cacheKey = "", version = null} = {}) {
|
||||
url = "https://git.scbox.xkeyc.cn/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales/" + fileName;
|
||||
if (cacheKey && cacheKey !== "") {
|
||||
const localVersion = await getLocalData(`${cacheKey}_version`);
|
||||
const data = await getLocalData(cacheKey);
|
||||
if (data && typeof data === 'object' && Object.keys(data).length > 0 && localVersion === version) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
const startTime = new Date();
|
||||
const response = await fetch(url, {method: 'GET', mode: 'cors'});
|
||||
const endTime = new Date();
|
||||
const data = await response.json();
|
||||
if (cacheKey && cacheKey !== "") {
|
||||
console.log(`update ${cacheKey} v == ${version} time == ${(endTime - startTime) / 1000}s`);
|
||||
await setLocalData(cacheKey, data);
|
||||
await setLocalData(`${cacheKey}_version`, version);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function getLocalData(key) {
|
||||
return new Promise((resolve) => {
|
||||
chrome.storage.local.get([key], (result) => {
|
||||
const data = result[key];
|
||||
resolve(data || null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setLocalData(key, data) {
|
||||
return new Promise((resolve) => {
|
||||
const newData = {};
|
||||
newData[key] = data;
|
||||
chrome.storage.local.set(newData, () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
chrome.contextMenus.create({
|
||||
id: "translate",
|
||||
title: "翻译本页面",
|
||||
contexts: ["page"]
|
||||
});
|
||||
|
||||
chrome.contextMenus.onClicked.addListener((info, tab) => {
|
||||
console.log("contextMenus", info, tab);
|
||||
_initLocalization("manual").then(data => {
|
||||
chrome.tabs.sendMessage(tab.id, {action: "_initTranslation", data});
|
||||
});
|
||||
});
|
@ -1,251 +0,0 @@
|
||||
let SCLocalizationReplaceLocalesMap = {};
|
||||
let SCLocalizationEnableSplitMode = false;
|
||||
|
||||
function InitWebLocalization() {
|
||||
// init script
|
||||
LocalizationWatchUpdate();
|
||||
// load Data
|
||||
_loadLocalizationData();
|
||||
}
|
||||
|
||||
function LocalizationWatchUpdate() {
|
||||
const m = window.MutationObserver || window.WebKitMutationObserver;
|
||||
const observer = new m(function (mutations, observer) {
|
||||
for (let mutationRecord of mutations) {
|
||||
for (let node of mutationRecord.addedNodes) {
|
||||
traverseElement(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(document.body, {
|
||||
subtree: true,
|
||||
characterData: true,
|
||||
childList: true,
|
||||
});
|
||||
|
||||
if (window.location.href.includes("robertsspaceindustries.com")) {
|
||||
console.log("SCLocalizationEnableSplitMode = true");
|
||||
SCLocalizationEnableSplitMode = true;
|
||||
}
|
||||
|
||||
if (window.location.hostname.includes("www.erkul.games")) {
|
||||
document.body.addEventListener("click", function (event) {
|
||||
setTimeout(function () {
|
||||
allTranslate().then(_ => {
|
||||
});
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function WebLocalizationUpdateReplaceWords(w) {
|
||||
let replaceWords = w.sort(function (a, b) {
|
||||
return b.word.length - a.word.length;
|
||||
});
|
||||
replaceWords.forEach(({ word, replacement }) => {
|
||||
SCLocalizationReplaceLocalesMap[word] = replacement;
|
||||
});
|
||||
if (window.location.hostname.startsWith("issue-council.robertsspaceindustries.com")) {
|
||||
SCLocalizationReplaceLocalesMap["save"] = "保存";
|
||||
}
|
||||
allTranslate().then(_ => {
|
||||
});
|
||||
// console.log("WebLocalizationUpdateReplaceWords ==" + w)
|
||||
}
|
||||
|
||||
async function allTranslate() {
|
||||
async function replaceTextNode(node1) {
|
||||
if (node1.nodeType === Node.TEXT_NODE) {
|
||||
node1.nodeValue = GetSCLocalizationTranslateString(node1.nodeValue);
|
||||
} else {
|
||||
for (let i = 0; i < node1.childNodes.length; i++) {
|
||||
await replaceTextNode(node1.childNodes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await replaceTextNode(document.body);
|
||||
}
|
||||
|
||||
function traverseElement(el) {
|
||||
if (!shouldTranslateEl(el)) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const child of el.childNodes) {
|
||||
if (["RELATIVE-TIME", "TIME-AGO"].includes(el.tagName)) {
|
||||
translateRelativeTimeEl(el);
|
||||
return;
|
||||
}
|
||||
|
||||
if (child.nodeType === Node.TEXT_NODE) {
|
||||
translateElement(child);
|
||||
} else if (child.nodeType === Node.ELEMENT_NODE) {
|
||||
if (child.tagName === "INPUT") {
|
||||
translateElement(child);
|
||||
} else {
|
||||
traverseElement(child);
|
||||
}
|
||||
} else {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function translateElement(el) {
|
||||
// Get the text field name
|
||||
let k;
|
||||
if (el.tagName === "INPUT") {
|
||||
if (el.type === 'button' || el.type === 'submit') {
|
||||
k = 'value';
|
||||
} else {
|
||||
k = 'placeholder';
|
||||
}
|
||||
} else {
|
||||
k = 'data';
|
||||
}
|
||||
el[k] = GetSCLocalizationTranslateString(el[k]);
|
||||
}
|
||||
|
||||
function translateRelativeTimeEl(el) {
|
||||
const lang = (navigator.language || navigator.userLanguage);
|
||||
const datetime = $(el).attr('datetime');
|
||||
$(el).text(timeago.format(datetime, lang.replace('-', '_')));
|
||||
}
|
||||
|
||||
function shouldTranslateEl(el) {
|
||||
const blockIds = [];
|
||||
const blockClass = [
|
||||
"css-truncate" // 过滤文件目录
|
||||
];
|
||||
const blockTags = ["IMG", "svg", "mat-icon"];
|
||||
if (blockTags.includes(el.tagName)) {
|
||||
return false;
|
||||
}
|
||||
if (el.id && blockIds.includes(el.id)) {
|
||||
return false;
|
||||
}
|
||||
if (el.classList) {
|
||||
for (let clazz of blockClass) {
|
||||
if (el.classList.contains(clazz)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function GetSCLocalizationTranslateString(txtSrc) {
|
||||
const key = txtSrc.toLowerCase().replace(/\xa0/g, ' ').replace(/\s{2,}/g, ' ').trim();
|
||||
const sourceKey = txtSrc.replace(/\xa0/g, ' ').replace(/\s{2,}/g, ' ').trim();
|
||||
let noTheKey = key.replace("the ", "");
|
||||
let noHorizontalKey = key.replace("- ", "");
|
||||
|
||||
if (SCLocalizationReplaceLocalesMap[key]) {
|
||||
txtSrc = SCLocalizationReplaceLocalesMap[key]
|
||||
} else if (SCLocalizationEnableSplitMode) {
|
||||
if (sourceKey.includes(" - ")) {
|
||||
let nodeValue = txtSrc
|
||||
let splitKey = sourceKey.split(" - ");
|
||||
if (splitKey[0].toLowerCase() === "upgrade" && key.includes("to") && key.endsWith("edition")) {
|
||||
// 升级包规则
|
||||
let noVersionStr = key.replace("STANDARD EDITION".toLowerCase(), "").replace("upgrade", "").replace("WARBOND EDITION".toLowerCase(), "")
|
||||
let shipNames = noVersionStr.split(" to ")
|
||||
let finalString = "升级包 " + GetSCLocalizationTranslateString(shipNames[0]) + " 到 " + GetSCLocalizationTranslateString(shipNames[1]);
|
||||
if (key.endsWith("WARBOND EDITION".toLowerCase())) {
|
||||
finalString = finalString + " 战争债券版"
|
||||
} else {
|
||||
finalString = finalString + " 标准版"
|
||||
}
|
||||
txtSrc = finalString
|
||||
} else {
|
||||
// 机库通用规则
|
||||
splitKey.forEach(function (splitKey) {
|
||||
if (SCLocalizationReplaceLocalesMap[splitKey.toLowerCase()]) {
|
||||
nodeValue = nodeValue.replace(splitKey, SCLocalizationReplaceLocalesMap[splitKey.toLowerCase()])
|
||||
} else {
|
||||
nodeValue = nodeValue.replace(splitKey, GetSCLocalizationTranslateString(splitKey))
|
||||
}
|
||||
});
|
||||
txtSrc = nodeValue
|
||||
}
|
||||
} else if (key.endsWith("starter pack") || key.endsWith("starter package")) {
|
||||
let shipName = key.replace("starter package", "").replace("starter pack", "").trim()
|
||||
if (SCLocalizationReplaceLocalesMap[shipName.toLowerCase()]) {
|
||||
shipName = SCLocalizationReplaceLocalesMap[shipName.toLowerCase()];
|
||||
}
|
||||
txtSrc = shipName + " 新手包";
|
||||
} else if (key.startsWith("the ") && SCLocalizationReplaceLocalesMap[noTheKey]) {
|
||||
txtSrc = SCLocalizationReplaceLocalesMap[noTheKey];
|
||||
} else if (key.startsWith("- ") && SCLocalizationReplaceLocalesMap[noHorizontalKey]) {
|
||||
txtSrc = "- " + SCLocalizationReplaceLocalesMap[noHorizontalKey];
|
||||
}
|
||||
}
|
||||
return txtSrc
|
||||
}
|
||||
|
||||
InitWebLocalization();
|
||||
|
||||
function _loadLocalizationData() {
|
||||
chrome.runtime.sendMessage({ action: "_loadLocalizationData", url: window.location.href }, function (response) {
|
||||
WebLocalizationUpdateReplaceWords(response.result);
|
||||
});
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
if (request.action === "_initTranslation") {
|
||||
SCLocalizationEnableSplitMode = true;
|
||||
WebLocalizationUpdateReplaceWords(request.data);
|
||||
}
|
||||
});
|
||||
|
||||
// 注入脚本到网页上下文
|
||||
const script = document.createElement('script');
|
||||
script.src = chrome.runtime.getURL('injected.js');
|
||||
script.onload = function () {
|
||||
this.remove();
|
||||
};
|
||||
(document.head || document.documentElement).appendChild(script);
|
||||
|
||||
// 监听来自网页的消息
|
||||
window.addEventListener('message', async (event) => {
|
||||
if (event.source !== window || !event.data || event.data.type !== 'SC_TRANSLATE_REQUEST') return;
|
||||
|
||||
console.log("event.data ==" + JSON.stringify(event.data));
|
||||
|
||||
const { action, payload, requestId } = event.data;
|
||||
|
||||
let response = { success: false };
|
||||
|
||||
if (action === 'translate') {
|
||||
try {
|
||||
SCLocalizationEnableSplitMode = true;
|
||||
chrome.runtime.sendMessage({ action: "_loadLocalizationData", url: "manual" }, function (response) {
|
||||
WebLocalizationUpdateReplaceWords(response.result);
|
||||
});
|
||||
} catch (error) {
|
||||
response = { success: false, error: error.message };
|
||||
}
|
||||
} else if (action === 'updateReplaceWords') {
|
||||
try {
|
||||
if (payload && payload.words && Array.isArray(payload.words)) {
|
||||
WebLocalizationUpdateReplaceWords(payload.words);
|
||||
response = { success: true };
|
||||
} else {
|
||||
response = { success: false, error: 'Invalid words format' };
|
||||
}
|
||||
} catch (error) {
|
||||
response = { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
// 发送响应回网页
|
||||
window.postMessage({
|
||||
type: 'SC_TRANSLATE_RESPONSE',
|
||||
requestId,
|
||||
response
|
||||
}, '*');
|
||||
});
|
||||
|
||||
window.postMessage({ type: 'SC-BOX-TRANSLATE-API-AVAILABLE' }, '*');
|
Binary file not shown.
Before Width: | Height: | Size: 12 KiB |
@ -1,22 +0,0 @@
|
||||
// 在网页上下文中定义一个API
|
||||
window.SCTranslateApi = {
|
||||
// 手动触发页面翻译
|
||||
translate: async () => {
|
||||
const requestId = Math.random().toString(36).substr(2);
|
||||
return new Promise((resolve) => {
|
||||
const handler = (event) => {
|
||||
if (event.data.type === 'SC_TRANSLATE_RESPONSE' && event.data.requestId === requestId) {
|
||||
window.removeEventListener('message', handler);
|
||||
resolve(event.data.response);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', handler);
|
||||
|
||||
window.postMessage({
|
||||
type: 'SC_TRANSLATE_REQUEST',
|
||||
action: 'translate',
|
||||
requestId
|
||||
}, '*');
|
||||
});
|
||||
}
|
||||
};
|
@ -1,62 +0,0 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "星际公民盒子浏览器拓展",
|
||||
"version": "0.0.11",
|
||||
"description": "为星际公民网站及工具站提供汉化",
|
||||
"author": "xkeyC",
|
||||
"icons": {
|
||||
"16": "icon.png",
|
||||
"48": "icon.png",
|
||||
"192": "icon.png"
|
||||
},
|
||||
"host_permissions": [
|
||||
"https://git.scbox.xkeyc.cn/*"
|
||||
],
|
||||
"permissions": [
|
||||
"storage",
|
||||
"contextMenus"
|
||||
],
|
||||
"action": {
|
||||
"default_popup": "popup.html"
|
||||
},
|
||||
"background": {
|
||||
"service_worker": "background.js"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"*://*/*"
|
||||
],
|
||||
"exclude_matches": [
|
||||
"https://robertsspaceindustries.com/spectrum/*"
|
||||
],
|
||||
"js": [
|
||||
"core.js",
|
||||
"thirdparty/timeago.full.min.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"matches": [
|
||||
"https://www.erkul.games/*"
|
||||
],
|
||||
"js": [
|
||||
"thirdparty/jquery.min.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"matches": [
|
||||
"https://robertsspaceindustries.com/*"
|
||||
],
|
||||
"js": [
|
||||
"rsi_hangar_fix.js"
|
||||
],
|
||||
"run_at": "document_idle"
|
||||
}
|
||||
],
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"resources": ["injected.js"],
|
||||
"matches": ["<all_urls>"]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>星际公民盒子浏览器拓展</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: 8px;
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
width: 250px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.card img,
|
||||
.card svg {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.card a {
|
||||
text-decoration: none;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.card h3,
|
||||
.card p {
|
||||
margin: 5px 0;
|
||||
/* 上下间距为5px,左右间距为0 */
|
||||
}
|
||||
|
||||
.card a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="card" style="padding-top: 0; padding-bottom: 0; border-radius: 0;">
|
||||
<a href="https://github.com/xkeyC/StarCitizenBoxBrowserEx" target="_blank">
|
||||
<div>
|
||||
<h2>星际公民盒子浏览器拓展</h2>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<a href="https://robertsspaceindustries.com/" target="_blank">
|
||||
<svg viewBox="0 0 56 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M16.0716 0C17.111 0 17.7697 0.734004 17.5824 1.65153L17.5516 1.77773L16.4646 5.68023C16.2499 6.48564 15.6763 7.15995 14.9845 7.52983L14.8228 7.6097L11.6546 9.08403L12.3485 11.8374C12.4102 12.0494 12.6179 12.227 12.8583 12.2638L12.9497 12.2708H15.0308L14.0135 16H10.7299C9.96799 16 9.22678 15.4621 8.98803 14.8024L8.94926 14.6774L7.95482 10.8185L5.17986 12.1191L4.11629 16H0L4.34743 0H16.0716ZM30.028 0L30.0255 0.00849999L29.0084 3.71374L29.0048 3.72704H29.0004L22.8229 3.71374C22.4538 3.71374 22.1768 3.84407 22.0843 4.19052C22.0024 4.49868 22.1027 4.73832 22.3854 4.94011L22.4999 5.01406L29.1008 9.10927C29.7285 9.49516 30.0921 10.3574 29.9828 11.0527L29.9546 11.1894L29.0084 14.6781C28.8348 15.3511 28.0883 15.9282 27.3084 15.9938L27.1619 16H18.8519L19.8686 12.2728H24.8772C25.2464 12.2728 25.5232 12.0346 25.5925 11.8178C25.6756 11.5644 25.6278 11.3636 25.3483 11.1522L25.2464 11.0812L18.5995 6.92095C17.9719 6.53476 17.6081 5.67281 17.7173 4.97743L17.7455 4.84076L18.6914 1.33023C18.8654 0.657352 19.5912 0.0802618 20.3495 0.0146972L20.492 0.00849999L30.0218 0H30.028ZM34.8758 0L39.0028 0.00849999L34.6207 16H30.4473L34.8566 0.00849999H34.8735L34.8758 0ZM17.698 12.2956L16.6916 16H16.0205L17.0206 12.2956H17.698ZM16.356 12.2956L15.313 16H14.5946L15.6471 12.3028L15.6493 12.2956H16.356ZM19.124 12.2956L18.0887 16H17.3625L18.398 12.2956H19.124ZM12.2017 3.70443H7.46927L6.45853 7.48768L12.0409 4.81988C12.5006 4.60106 12.6614 4.33872 12.7304 4.12006C12.8222 3.83596 12.5694 3.70443 12.2017 3.70443ZM34.1379 0L33.1305 3.70443H32.4604L33.474 0H34.1379ZM32.712 0L31.7062 3.70443H31.0345L32.0511 0H32.712ZM31.3537 0L31.3515 0.00844828H31.37L30.3313 3.69121L30.3277 3.70443H29.6086L29.6121 3.69121L30.6322 0.00844828L30.6346 0H31.3537Z"
|
||||
fill="currentColor"></path>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M44.0993 0.5C45.1052 0.5 45.71 0.718656 46.0714 1.07635C46.4317 1.43287 46.6502 2.02678 46.6502 3.01365C46.6502 4.00008 46.4317 4.58521 46.0739 4.93447C45.7133 5.28641 45.1085 5.5 44.0993 5.5C43.0905 5.5 42.4701 5.28657 42.0962 4.9303C41.7277 4.57908 41.5 3.99382 41.5 3.01365C41.5 2.03297 41.7277 1.43898 42.0987 1.08055C42.4734 0.718531 43.0938 0.5 44.0993 0.5ZM47.1502 3.01365C47.1502 0.918004 46.2283 0 44.0993 0C41.9703 0 41 0.918004 41 3.01365C41 5.10816 41.9703 6 44.0993 6C46.2283 6 47.1502 5.10816 47.1502 3.01365ZM42.7675 1.363C43.2445 1.318 43.717 1.3 44.194 1.3C45.157 1.3 45.4855 1.633 45.4855 2.5105C45.4855 3.154 45.319 3.4555 44.842 3.577L45.607 4.7965C45.643 4.846 45.6205 4.8865 45.553 4.8865H44.725C44.6215 4.8865 44.59 4.855 44.545 4.7875L43.816 3.6355H43.645V4.8145C43.645 4.873 43.6315 4.8865 43.5775 4.8865H42.7675C42.7135 4.8865 42.7 4.873 42.7 4.8145V1.4215C42.7 1.381 42.7135 1.3675 42.7675 1.363ZM44.527 2.542C44.527 2.2495 44.428 2.1235 44.0905 2.1235H43.645V2.9425H44.0905C44.428 2.9425 44.527 2.839 44.527 2.542Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
<h3>星际公民官网</h3>
|
||||
<p>罗伯茨航天工业公司,万物的起源</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<a href="https://uexcorp.space" target="_blank">
|
||||
<img src="https://assets.uexcorp.space/img/logo.svg" alt="">
|
||||
<h3>UEX</h3>
|
||||
<p>采矿、精炼、贸易计算器、价格、船信息</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<a href="https://www.erkul.games/live/calculator" target="_blank">
|
||||
<img src="https://www.erkul.games/assets/icons/icon-512x512.png">
|
||||
<h3>DPS 计算器</h3>
|
||||
<p>在线改船,查询伤害数值和配件购买地点</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<a href="https://ccugame.app" target="_blank">
|
||||
<img src="https://ccugame.app/assets/images/logo/logo.png">
|
||||
<h3>CCUGame(官方汉化)</h3>
|
||||
<p>资产管理和舰队规划,一定要理性消费.jpg</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,93 +0,0 @@
|
||||
// from https://github.com/cfdxkk/RSI-Hangar-Button
|
||||
// LICENSE GLWT(Good Luck With That) Public License
|
||||
(function () {
|
||||
/**
|
||||
* 寻找元素直到元素被加载
|
||||
* @param dom 查找的根元素
|
||||
* @param selector 元素的查找
|
||||
* @param callback 查找到的回调
|
||||
* @param interval 查找的间隔,默认 100 毫秒
|
||||
*/
|
||||
function waitForElement(dom, selector, callback, interval = 100) {
|
||||
const checkExist = setInterval(() => {
|
||||
const element = dom.querySelector(selector)
|
||||
if (element) {
|
||||
clearInterval(checkExist) // 停止轮询
|
||||
callback(element)
|
||||
}
|
||||
}, interval)
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始监听抽屉,如果监听到点击事件,则添加按钮
|
||||
* @param element
|
||||
*/
|
||||
function startObserve(element) {
|
||||
// 创建一个 MutationObserver 实例,监听元素的子元素变化
|
||||
const observer = new MutationObserver((mutationsList) => {
|
||||
for (const mutation of mutationsList) {
|
||||
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
|
||||
mutation.addedNodes.forEach(node => {
|
||||
if (node.nodeType === 1) { // 只处理元素节点 (忽略文本节点)
|
||||
waitForElement(node, "a[data-cy-id=\"button\"][href=\"/account/settings\"]", (button) => {
|
||||
copyAndAddButton(button)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 监听子节点变化,并对子树内的变化也进行监听
|
||||
observer.observe(element, { childList: true, subtree: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制原有按钮,将其修改为机库按钮并插入到原按钮的上方
|
||||
* 在插入前先检查是否已经存在对应的按钮
|
||||
* @param {HTMLElement} button 原始按钮
|
||||
*/
|
||||
function copyAndAddButton(button) {
|
||||
if (!button) return
|
||||
|
||||
// 如果已经存在 href 为 /account/pledges 的按钮,则不再添加
|
||||
if (button.parentNode.querySelector('a[data-cy-id="button"][href="/account/pledges"]')) {
|
||||
return
|
||||
}
|
||||
// 复制元素
|
||||
const hangarButton = button.cloneNode(true)
|
||||
|
||||
// 修改 href
|
||||
hangarButton.href = "/account/pledges"
|
||||
|
||||
// 查找按钮中的文本部分
|
||||
const hangarButtonText = hangarButton.querySelector('span[data-cy-id="button__text"]')
|
||||
|
||||
// 修改文本
|
||||
if (hangarButtonText) {
|
||||
hangarButtonText.innerText = "My Hangar"
|
||||
}
|
||||
|
||||
// 查找按钮中的图标部分
|
||||
const hangarButtonIcon = hangarButton.querySelector('i[data-cy-id="button__icon"]')
|
||||
|
||||
// 修改图标
|
||||
if (hangarButtonIcon) {
|
||||
hangarButtonIcon.className = "a-button__icon a-icon -gridView"
|
||||
}
|
||||
|
||||
// 插入到目标元素的前方
|
||||
button.parentNode.insertBefore(hangarButton, button)
|
||||
}
|
||||
|
||||
// 开始查找抽屉,如果找到执行监听回调
|
||||
waitForElement(document, "#sidePanel", (risSidePanel) => {
|
||||
startObserve(risSidePanel)
|
||||
|
||||
// 初始检查:防止首次打开抽屉时按钮已经存在,MutationObserver 不触发
|
||||
const button = sidePanel.querySelector('a[data-cy-id="button"][href="/account/settings"]')
|
||||
if (button) {
|
||||
copyAndAddButton(button)
|
||||
}
|
||||
})
|
||||
})()
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,153 +0,0 @@
|
||||
let dataVersion = null
|
||||
|
||||
chrome.runtime.onInstalled.addListener(function () {
|
||||
_checkVersion().then(_ => {
|
||||
});
|
||||
console.log("SWTT init");
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
||||
if (request.action === "_loadLocalizationData") {
|
||||
_initLocalization(request.url).then(data => {
|
||||
sendResponse({result: data});
|
||||
});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
async function _checkVersion() {
|
||||
dataVersion = await _getJsonData("versions.json");
|
||||
console.log("Localization Version ===");
|
||||
console.log(dataVersion);
|
||||
}
|
||||
|
||||
async function _initLocalization(url) {
|
||||
console.log("url ===" + url);
|
||||
if (dataVersion == null) {
|
||||
await _checkVersion();
|
||||
return _initLocalization(url);
|
||||
}
|
||||
let v = dataVersion
|
||||
// TODO check version
|
||||
let data = {};
|
||||
|
||||
if (url.includes("robertsspaceindustries.com")) {
|
||||
data["zh-CN"] = await _getJsonData("zh-CN-rsi.json", {cacheKey: "zh-CN", version: v.rsi});
|
||||
data["concierge"] = await _getJsonData("concierge.json", {cacheKey: "concierge", version: v.concierge});
|
||||
data["orgs"] = await _getJsonData("orgs.json", v.orgs);
|
||||
data["address"] = await _getJsonData("addresses.json", {cacheKey: "orgs", version: v.addresses});
|
||||
data["hangar"] = await _getJsonData("hangar.json", {cacheKey: "hangar", version: v.hangar});
|
||||
} else if (url.includes("uexcorp.space")) {
|
||||
data["UEX"] = await _getJsonData("zh-CN-uex.json", {cacheKey: "uex", version: v.uex});
|
||||
} else if (url.includes("erkul.games")) {
|
||||
data["DPS"] = await _getJsonData("zh-CN-dps.json", {cacheKey: "dps", version: v.dps});
|
||||
}
|
||||
// update data
|
||||
let replaceWords = [];
|
||||
|
||||
function addLocalizationResource(key) {
|
||||
replaceWords.push(...getLocalizationResource(data, key));
|
||||
}
|
||||
|
||||
if (url.includes("robertsspaceindustries.com")) {
|
||||
const org = "https://robertsspaceindustries.com/orgs";
|
||||
const citizens = "https://robertsspaceindustries.com/citizens";
|
||||
const organization = "https://robertsspaceindustries.com/account/organization";
|
||||
const concierge = "https://robertsspaceindustries.com/account/concierge";
|
||||
const referral = "https://robertsspaceindustries.com/account/referral-program";
|
||||
const address = "https://robertsspaceindustries.com/account/addresses";
|
||||
const hangar = "https://robertsspaceindustries.com/account/pledges";
|
||||
const spectrum = "https://robertsspaceindustries.com/spectrum/community/";
|
||||
if (url.startsWith(spectrum)) {
|
||||
return;
|
||||
}
|
||||
addLocalizationResource("zh-CN");
|
||||
if (url.startsWith(org) || url.startsWith(citizens) || url.startsWith(organization)) {
|
||||
replaceWords.push({"word": 'members', "replacement": '名成员'});
|
||||
addLocalizationResource("orgs");
|
||||
}
|
||||
if (url.startsWith(address)) {
|
||||
addLocalizationResource("address");
|
||||
}
|
||||
|
||||
if (url.startsWith(referral)) {
|
||||
replaceWords.push(
|
||||
{"word": 'Total recruits: ', "replacement": '总邀请数:'},
|
||||
{"word": 'Prospects ', "replacement": '未完成的邀请'},
|
||||
{"word": 'Recruits', "replacement": '已完成的邀请'}
|
||||
);
|
||||
}
|
||||
|
||||
if (url.startsWith(concierge)) {
|
||||
replaceWords = [];
|
||||
addLocalizationResource("concierge");
|
||||
}
|
||||
|
||||
if (url.startsWith(hangar)) {
|
||||
addLocalizationResource("hangar");
|
||||
}
|
||||
} else if (url.includes("uexcorp.space")) {
|
||||
addLocalizationResource("UEX");
|
||||
} else if (url.includes("erkul.games")) {
|
||||
addLocalizationResource("DPS");
|
||||
}
|
||||
return replaceWords;
|
||||
}
|
||||
|
||||
|
||||
function getLocalizationResource(localizationResource, key) {
|
||||
const localizations = [];
|
||||
const dict = localizationResource[key];
|
||||
if (typeof dict === "object") {
|
||||
for (const [k, v] of Object.entries(dict)) {
|
||||
const trimmedKey = k
|
||||
.toString()
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/\xa0/g, ' ')
|
||||
.replace(/\s{2,}/g, ' ');
|
||||
localizations.push({"word": trimmedKey, "replacement": v.toString()});
|
||||
}
|
||||
}
|
||||
return localizations;
|
||||
}
|
||||
|
||||
async function _getJsonData(fileName, {cacheKey = "", version = null} = {}) {
|
||||
url = "https://git.scbox.xkeyc.cn/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales/" + fileName;
|
||||
if (cacheKey && cacheKey !== "") {
|
||||
const localVersion = await getLocalData(`${cacheKey}_version`);
|
||||
const data = await getLocalData(cacheKey);
|
||||
if (data && typeof data === 'object' && Object.keys(data).length > 0 && localVersion === version) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
const startTime = new Date();
|
||||
const response = await fetch(url, {method: 'GET', mode: 'cors'});
|
||||
const endTime = new Date();
|
||||
const data = await response.json();
|
||||
if (cacheKey && cacheKey !== "") {
|
||||
console.log(`update ${cacheKey} v == ${version} time == ${(endTime - startTime) / 1000}s`);
|
||||
await setLocalData(cacheKey, data);
|
||||
await setLocalData(`${cacheKey}_version`, version);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function getLocalData(key) {
|
||||
return new Promise((resolve) => {
|
||||
chrome.storage.local.get([key], (result) => {
|
||||
const data = result[key];
|
||||
resolve(data || null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setLocalData(key, data) {
|
||||
return new Promise((resolve) => {
|
||||
const newData = {};
|
||||
newData[key] = data;
|
||||
chrome.storage.local.set(newData, () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
@ -1,194 +0,0 @@
|
||||
let SCLocalizationReplaceLocalesMap = {};
|
||||
let SCLocalizationEnableSplitMode = false;
|
||||
|
||||
function InitWebLocalization() {
|
||||
// init script
|
||||
LocalizationWatchUpdate();
|
||||
// load Data
|
||||
_loadLocalizationData();
|
||||
}
|
||||
|
||||
function LocalizationWatchUpdate() {
|
||||
const m = window.MutationObserver || window.WebKitMutationObserver;
|
||||
const observer = new m(function (mutations, observer) {
|
||||
for (let mutationRecord of mutations) {
|
||||
for (let node of mutationRecord.addedNodes) {
|
||||
traverseElement(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(document.body, {
|
||||
subtree: true,
|
||||
characterData: true,
|
||||
childList: true,
|
||||
});
|
||||
|
||||
if (window.location.href.includes("robertsspaceindustries.com")) {
|
||||
console.log("SCLocalizationEnableSplitMode = true");
|
||||
SCLocalizationEnableSplitMode = true;
|
||||
}
|
||||
|
||||
if (window.location.hostname.includes("www.erkul.games")) {
|
||||
document.body.addEventListener("click", function (event) {
|
||||
setTimeout(function () {
|
||||
allTranslate().then(_ => {
|
||||
});
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function WebLocalizationUpdateReplaceWords(w) {
|
||||
let replaceWords = w.sort(function (a, b) {
|
||||
return b.word.length - a.word.length;
|
||||
});
|
||||
replaceWords.forEach(({word, replacement}) => {
|
||||
SCLocalizationReplaceLocalesMap[word] = replacement;
|
||||
});
|
||||
if (window.location.hostname.startsWith("issue-council.robertsspaceindustries.com")) {
|
||||
SCLocalizationReplaceLocalesMap["save"] = "保存";
|
||||
}
|
||||
allTranslate().then(_ => {
|
||||
});
|
||||
// console.log("WebLocalizationUpdateReplaceWords ==" + w)
|
||||
}
|
||||
|
||||
async function allTranslate() {
|
||||
async function replaceTextNode(node1) {
|
||||
if (node1.nodeType === Node.TEXT_NODE) {
|
||||
node1.nodeValue = GetSCLocalizationTranslateString(node1.nodeValue);
|
||||
} else {
|
||||
for (let i = 0; i < node1.childNodes.length; i++) {
|
||||
await replaceTextNode(node1.childNodes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await replaceTextNode(document.body);
|
||||
}
|
||||
|
||||
function traverseElement(el) {
|
||||
if (!shouldTranslateEl(el)) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const child of el.childNodes) {
|
||||
if (["RELATIVE-TIME", "TIME-AGO"].includes(el.tagName)) {
|
||||
translateRelativeTimeEl(el);
|
||||
return;
|
||||
}
|
||||
|
||||
if (child.nodeType === Node.TEXT_NODE) {
|
||||
translateElement(child);
|
||||
} else if (child.nodeType === Node.ELEMENT_NODE) {
|
||||
if (child.tagName === "INPUT") {
|
||||
translateElement(child);
|
||||
} else {
|
||||
traverseElement(child);
|
||||
}
|
||||
} else {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function translateElement(el) {
|
||||
// Get the text field name
|
||||
let k;
|
||||
if (el.tagName === "INPUT") {
|
||||
if (el.type === 'button' || el.type === 'submit') {
|
||||
k = 'value';
|
||||
} else {
|
||||
k = 'placeholder';
|
||||
}
|
||||
} else {
|
||||
k = 'data';
|
||||
}
|
||||
el[k] = GetSCLocalizationTranslateString(el[k]);
|
||||
}
|
||||
|
||||
function translateRelativeTimeEl(el) {
|
||||
const lang = (navigator.language || navigator.userLanguage);
|
||||
const datetime = $(el).attr('datetime');
|
||||
$(el).text(timeago.format(datetime, lang.replace('-', '_')));
|
||||
}
|
||||
|
||||
function shouldTranslateEl(el) {
|
||||
const blockIds = [];
|
||||
const blockClass = [
|
||||
"css-truncate" // 过滤文件目录
|
||||
];
|
||||
const blockTags = ["IMG", "svg", "mat-icon"];
|
||||
if (blockTags.includes(el.tagName)) {
|
||||
return false;
|
||||
}
|
||||
if (el.id && blockIds.includes(el.id)) {
|
||||
return false;
|
||||
}
|
||||
if (el.classList) {
|
||||
for (let clazz of blockClass) {
|
||||
if (el.classList.contains(clazz)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function GetSCLocalizationTranslateString(txtSrc) {
|
||||
const key = txtSrc.toLowerCase().replace(/\xa0/g, ' ').replace(/\s{2,}/g, ' ').trim();
|
||||
const sourceKey = txtSrc.replace(/\xa0/g, ' ').replace(/\s{2,}/g, ' ').trim();
|
||||
let noTheKey = key.replace("the ", "");
|
||||
let noHorizontalKey = key.replace("- ", "");
|
||||
|
||||
if (SCLocalizationReplaceLocalesMap[key]) {
|
||||
txtSrc = SCLocalizationReplaceLocalesMap[key]
|
||||
} else if (SCLocalizationEnableSplitMode) {
|
||||
if (sourceKey.includes(" - ")) {
|
||||
let nodeValue = txtSrc
|
||||
let splitKey = sourceKey.split(" - ");
|
||||
if (splitKey[0].toLowerCase() === "upgrade" && key.includes("to") && key.endsWith("edition")) {
|
||||
// 升级包规则
|
||||
let noVersionStr = key.replace("STANDARD EDITION".toLowerCase(), "").replace("upgrade", "").replace("WARBOND EDITION".toLowerCase(), "")
|
||||
let shipNames = noVersionStr.split(" to ")
|
||||
let finalString = "升级包 " + GetSCLocalizationTranslateString(shipNames[0]) + " 到 " + GetSCLocalizationTranslateString(shipNames[1]);
|
||||
if (key.endsWith("WARBOND EDITION".toLowerCase())) {
|
||||
finalString = finalString + " 战争债券版"
|
||||
} else {
|
||||
finalString = finalString + " 标准版"
|
||||
}
|
||||
txtSrc = finalString
|
||||
} else {
|
||||
// 机库通用规则
|
||||
splitKey.forEach(function (splitKey) {
|
||||
if (SCLocalizationReplaceLocalesMap[splitKey.toLowerCase()]) {
|
||||
nodeValue = nodeValue.replace(splitKey, SCLocalizationReplaceLocalesMap[splitKey.toLowerCase()])
|
||||
} else {
|
||||
nodeValue = nodeValue.replace(splitKey, GetSCLocalizationTranslateString(splitKey))
|
||||
}
|
||||
});
|
||||
txtSrc = nodeValue
|
||||
}
|
||||
} else if (key.endsWith("starter pack") || key.endsWith("starter package")) {
|
||||
let shipName = key.replace("starter package", "").replace("starter pack", "").trim()
|
||||
if (SCLocalizationReplaceLocalesMap[shipName.toLowerCase()]) {
|
||||
shipName = SCLocalizationReplaceLocalesMap[shipName.toLowerCase()];
|
||||
}
|
||||
txtSrc = shipName + " 新手包";
|
||||
} else if (key.startsWith("the ") && SCLocalizationReplaceLocalesMap[noTheKey]) {
|
||||
txtSrc = SCLocalizationReplaceLocalesMap[noTheKey];
|
||||
} else if (key.startsWith("- ") && SCLocalizationReplaceLocalesMap[noHorizontalKey]) {
|
||||
txtSrc = "- " + SCLocalizationReplaceLocalesMap[noHorizontalKey];
|
||||
}
|
||||
}
|
||||
return txtSrc
|
||||
}
|
||||
|
||||
InitWebLocalization();
|
||||
|
||||
function _loadLocalizationData() {
|
||||
chrome.runtime.sendMessage({action: "_loadLocalizationData", url: window.location.href}, function (response) {
|
||||
WebLocalizationUpdateReplaceWords(response.result);
|
||||
});
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 12 KiB |
@ -1,57 +0,0 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "星际公民盒子浏览器拓展",
|
||||
"version": "0.0.11",
|
||||
"description": "为星际公民网站及工具站提供汉化",
|
||||
"author": "xkeyC",
|
||||
"icons": {
|
||||
"192": "icon.png"
|
||||
},
|
||||
"permissions": [
|
||||
"storage",
|
||||
"https://git.scbox.xkeyc.cn/*"
|
||||
],
|
||||
"browser_action": {
|
||||
"default_icon": "icon.png",
|
||||
"default_popup": "popup.html"
|
||||
},
|
||||
"background": {
|
||||
"scripts": [
|
||||
"background.js"
|
||||
]
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"https://robertsspaceindustries.com/*",
|
||||
"https://*.robertsspaceindustries.com/*",
|
||||
"https://www.erkul.games/*",
|
||||
"https://uexcorp.space/*"
|
||||
],
|
||||
"exclude_matches": [
|
||||
"https://robertsspaceindustries.com/spectrum/*"
|
||||
],
|
||||
"js": [
|
||||
"core.js",
|
||||
"thirdparty/timeago.full.min.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"matches": [
|
||||
"https://www.erkul.games/*"
|
||||
],
|
||||
"js": [
|
||||
"thirdparty/jquery.min.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"matches": [
|
||||
"https://robertsspaceindustries.com/*"
|
||||
],
|
||||
"js": [
|
||||
"rsi_hangar_fix.js"
|
||||
],
|
||||
"run_at": "document_idle"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>星际公民盒子浏览器拓展</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: 8px;
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
padding: 10px;
|
||||
margin: 10px;
|
||||
width: 250px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.card img,
|
||||
.card svg {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.card a {
|
||||
text-decoration: none;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.card h3,
|
||||
.card p {
|
||||
margin: 5px 0;
|
||||
/* 上下间距为5px,左右间距为0 */
|
||||
}
|
||||
|
||||
.card a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="card" style="padding-top: 0; padding-bottom: 0; border-radius: 0;">
|
||||
<a href="https://github.com/xkeyC/StarCitizenBoxBrowserEx" target="_blank">
|
||||
<div>
|
||||
<h2>星际公民盒子浏览器拓展</h2>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<a href="https://robertsspaceindustries.com/" target="_blank">
|
||||
<svg viewBox="0 0 56 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M16.0716 0C17.111 0 17.7697 0.734004 17.5824 1.65153L17.5516 1.77773L16.4646 5.68023C16.2499 6.48564 15.6763 7.15995 14.9845 7.52983L14.8228 7.6097L11.6546 9.08403L12.3485 11.8374C12.4102 12.0494 12.6179 12.227 12.8583 12.2638L12.9497 12.2708H15.0308L14.0135 16H10.7299C9.96799 16 9.22678 15.4621 8.98803 14.8024L8.94926 14.6774L7.95482 10.8185L5.17986 12.1191L4.11629 16H0L4.34743 0H16.0716ZM30.028 0L30.0255 0.00849999L29.0084 3.71374L29.0048 3.72704H29.0004L22.8229 3.71374C22.4538 3.71374 22.1768 3.84407 22.0843 4.19052C22.0024 4.49868 22.1027 4.73832 22.3854 4.94011L22.4999 5.01406L29.1008 9.10927C29.7285 9.49516 30.0921 10.3574 29.9828 11.0527L29.9546 11.1894L29.0084 14.6781C28.8348 15.3511 28.0883 15.9282 27.3084 15.9938L27.1619 16H18.8519L19.8686 12.2728H24.8772C25.2464 12.2728 25.5232 12.0346 25.5925 11.8178C25.6756 11.5644 25.6278 11.3636 25.3483 11.1522L25.2464 11.0812L18.5995 6.92095C17.9719 6.53476 17.6081 5.67281 17.7173 4.97743L17.7455 4.84076L18.6914 1.33023C18.8654 0.657352 19.5912 0.0802618 20.3495 0.0146972L20.492 0.00849999L30.0218 0H30.028ZM34.8758 0L39.0028 0.00849999L34.6207 16H30.4473L34.8566 0.00849999H34.8735L34.8758 0ZM17.698 12.2956L16.6916 16H16.0205L17.0206 12.2956H17.698ZM16.356 12.2956L15.313 16H14.5946L15.6471 12.3028L15.6493 12.2956H16.356ZM19.124 12.2956L18.0887 16H17.3625L18.398 12.2956H19.124ZM12.2017 3.70443H7.46927L6.45853 7.48768L12.0409 4.81988C12.5006 4.60106 12.6614 4.33872 12.7304 4.12006C12.8222 3.83596 12.5694 3.70443 12.2017 3.70443ZM34.1379 0L33.1305 3.70443H32.4604L33.474 0H34.1379ZM32.712 0L31.7062 3.70443H31.0345L32.0511 0H32.712ZM31.3537 0L31.3515 0.00844828H31.37L30.3313 3.69121L30.3277 3.70443H29.6086L29.6121 3.69121L30.6322 0.00844828L30.6346 0H31.3537Z"
|
||||
fill="currentColor"></path>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M44.0993 0.5C45.1052 0.5 45.71 0.718656 46.0714 1.07635C46.4317 1.43287 46.6502 2.02678 46.6502 3.01365C46.6502 4.00008 46.4317 4.58521 46.0739 4.93447C45.7133 5.28641 45.1085 5.5 44.0993 5.5C43.0905 5.5 42.4701 5.28657 42.0962 4.9303C41.7277 4.57908 41.5 3.99382 41.5 3.01365C41.5 2.03297 41.7277 1.43898 42.0987 1.08055C42.4734 0.718531 43.0938 0.5 44.0993 0.5ZM47.1502 3.01365C47.1502 0.918004 46.2283 0 44.0993 0C41.9703 0 41 0.918004 41 3.01365C41 5.10816 41.9703 6 44.0993 6C46.2283 6 47.1502 5.10816 47.1502 3.01365ZM42.7675 1.363C43.2445 1.318 43.717 1.3 44.194 1.3C45.157 1.3 45.4855 1.633 45.4855 2.5105C45.4855 3.154 45.319 3.4555 44.842 3.577L45.607 4.7965C45.643 4.846 45.6205 4.8865 45.553 4.8865H44.725C44.6215 4.8865 44.59 4.855 44.545 4.7875L43.816 3.6355H43.645V4.8145C43.645 4.873 43.6315 4.8865 43.5775 4.8865H42.7675C42.7135 4.8865 42.7 4.873 42.7 4.8145V1.4215C42.7 1.381 42.7135 1.3675 42.7675 1.363ZM44.527 2.542C44.527 2.2495 44.428 2.1235 44.0905 2.1235H43.645V2.9425H44.0905C44.428 2.9425 44.527 2.839 44.527 2.542Z"
|
||||
fill="currentColor"></path>
|
||||
</svg>
|
||||
<h3>星际公民官网</h3>
|
||||
<p>罗伯茨航天工业公司,万物的起源</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<a href="https://uexcorp.space" target="_blank">
|
||||
<img src="https://assets.uexcorp.space/img/logo.svg" alt="">
|
||||
<h3>UEX</h3>
|
||||
<p>采矿、精炼、贸易计算器、价格、船信息</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<a href="https://www.erkul.games/live/calculator" target="_blank">
|
||||
<img src="https://www.erkul.games/assets/icons/icon-512x512.png">
|
||||
<h3>DPS 计算器</h3>
|
||||
<p>在线改船,查询伤害数值和配件购买地点</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<a href="https://ccugame.app" target="_blank">
|
||||
<img src="https://ccugame.app/assets/images/logo/logo.png">
|
||||
<h3>CCUGame(官方汉化)</h3>
|
||||
<p>资产管理和舰队规划,一定要理性消费.jpg</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,4 +1,20 @@
|
||||
let dataVersion = null
|
||||
interface VersionData {
|
||||
rsi: string;
|
||||
concierge: string;
|
||||
orgs: string;
|
||||
addresses: string;
|
||||
hangar: string;
|
||||
uex: string;
|
||||
dps: string;
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
interface ReplaceWord {
|
||||
word: string;
|
||||
replacement: string;
|
||||
}
|
||||
|
||||
let dataVersion: VersionData | null = null
|
||||
|
||||
chrome.runtime.onInstalled.addListener(function () {
|
||||
_checkVersion().then(_ => {
|
||||
@ -15,13 +31,13 @@ chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
|
||||
}
|
||||
});
|
||||
|
||||
async function _checkVersion() {
|
||||
dataVersion = await _getJsonData("versions.json");
|
||||
async function _checkVersion(): Promise<void> {
|
||||
dataVersion = await _getJsonData("versions.json") as VersionData;
|
||||
console.log("Localization Version ===");
|
||||
console.log(dataVersion);
|
||||
}
|
||||
|
||||
async function _initLocalization(url) {
|
||||
async function _initLocalization(url: string): Promise<ReplaceWord[]> {
|
||||
console.log("url ===" + url);
|
||||
if (dataVersion == null) {
|
||||
await _checkVersion();
|
||||
@ -29,12 +45,12 @@ async function _initLocalization(url) {
|
||||
}
|
||||
let v = dataVersion
|
||||
// TODO check version
|
||||
let data = {};
|
||||
let data: Record<string, any> = {};
|
||||
|
||||
if (url.includes("robertsspaceindustries.com") || url.includes("manual")) {
|
||||
data["zh-CN"] = await _getJsonData("zh-CN-rsi.json", {cacheKey: "zh-CN", version: v.rsi});
|
||||
data["concierge"] = await _getJsonData("concierge.json", {cacheKey: "concierge", version: v.concierge});
|
||||
data["orgs"] = await _getJsonData("orgs.json", v.orgs);
|
||||
data["orgs"] = await _getJsonData("orgs.json", {cacheKey: "orgs", version: v.orgs});
|
||||
data["address"] = await _getJsonData("addresses.json", {cacheKey: "orgs", version: v.addresses});
|
||||
data["hangar"] = await _getJsonData("hangar.json", {cacheKey: "hangar", version: v.hangar});
|
||||
} else if (url.includes("uexcorp.space")) {
|
||||
@ -43,9 +59,9 @@ async function _initLocalization(url) {
|
||||
data["DPS"] = await _getJsonData("zh-CN-dps.json", {cacheKey: "dps", version: v.dps});
|
||||
}
|
||||
// update data
|
||||
let replaceWords = [];
|
||||
let replaceWords: ReplaceWord[] = [];
|
||||
|
||||
function addLocalizationResource(key) {
|
||||
function addLocalizationResource(key: string): void {
|
||||
replaceWords.push(...getLocalizationResource(data, key));
|
||||
}
|
||||
|
||||
@ -59,7 +75,7 @@ async function _initLocalization(url) {
|
||||
const hangar = "https://robertsspaceindustries.com/account/pledges";
|
||||
const spectrum = "https://robertsspaceindustries.com/spectrum/community/";
|
||||
if (url.startsWith(spectrum)) {
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
addLocalizationResource("zh-CN");
|
||||
if (url.startsWith(org) || url.startsWith(citizens) || url.startsWith(organization)) {
|
||||
@ -95,8 +111,8 @@ async function _initLocalization(url) {
|
||||
}
|
||||
|
||||
|
||||
function getLocalizationResource(localizationResource, key) {
|
||||
const localizations = [];
|
||||
function getLocalizationResource(localizationResource: Record<string, any>, key: string): ReplaceWord[] {
|
||||
const localizations: ReplaceWord[] = [];
|
||||
const dict = localizationResource[key];
|
||||
if (typeof dict === "object") {
|
||||
for (const [k, v] of Object.entries(dict)) {
|
||||
@ -106,14 +122,20 @@ function getLocalizationResource(localizationResource, key) {
|
||||
.toLowerCase()
|
||||
.replace(/\xa0/g, ' ')
|
||||
.replace(/\s{2,}/g, ' ');
|
||||
localizations.push({"word": trimmedKey, "replacement": v.toString()});
|
||||
localizations.push({"word": trimmedKey, "replacement": String(v)});
|
||||
}
|
||||
}
|
||||
return localizations;
|
||||
}
|
||||
|
||||
async function _getJsonData(fileName, {cacheKey = "", version = null} = {}) {
|
||||
url = "https://git.scbox.xkeyc.cn/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales/" + fileName;
|
||||
interface JsonDataOptions {
|
||||
cacheKey?: string;
|
||||
version?: string | null;
|
||||
}
|
||||
|
||||
async function _getJsonData(fileName: string, options: JsonDataOptions = {}): Promise<any> {
|
||||
const { cacheKey = "", version = null } = options;
|
||||
const url = "https://git.scbox.xkeyc.cn/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales/" + fileName;
|
||||
if (cacheKey && cacheKey !== "") {
|
||||
const localVersion = await getLocalData(`${cacheKey}_version`);
|
||||
const data = await getLocalData(cacheKey);
|
||||
@ -126,14 +148,15 @@ async function _getJsonData(fileName, {cacheKey = "", version = null} = {}) {
|
||||
const endTime = new Date();
|
||||
const data = await response.json();
|
||||
if (cacheKey && cacheKey !== "") {
|
||||
console.log(`update ${cacheKey} v == ${version} time == ${(endTime - startTime) / 1000}s`);
|
||||
const timeDiff = endTime.getTime() - startTime.getTime();
|
||||
console.log(`update ${cacheKey} v == ${version} time == ${timeDiff / 1000}s`);
|
||||
await setLocalData(cacheKey, data);
|
||||
await setLocalData(`${cacheKey}_version`, version);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function getLocalData(key) {
|
||||
function getLocalData(key: string): Promise<any> {
|
||||
return new Promise((resolve) => {
|
||||
chrome.storage.local.get([key], (result) => {
|
||||
const data = result[key];
|
||||
@ -142,9 +165,9 @@ function getLocalData(key) {
|
||||
});
|
||||
}
|
||||
|
||||
function setLocalData(key, data) {
|
||||
return new Promise((resolve) => {
|
||||
const newData = {};
|
||||
function setLocalData(key: string, data: any): Promise<void> {
|
||||
return new Promise<void>((resolve) => {
|
||||
const newData: Record<string, any> = {};
|
||||
newData[key] = data;
|
||||
chrome.storage.local.set(newData, () => {
|
||||
resolve();
|
||||
@ -156,18 +179,20 @@ chrome.runtime.onInstalled.addListener(function () {
|
||||
chrome.contextMenus.create({
|
||||
id: "translate",
|
||||
title: "切换翻译",
|
||||
contexts: ["page"]
|
||||
contexts: ["all"]
|
||||
});
|
||||
});
|
||||
|
||||
chrome.contextMenus.onClicked.addListener((info, tab) => {
|
||||
console.log("contextMenus", info, tab);
|
||||
let passedUrl = "manual"
|
||||
let passedUrl = "manual";
|
||||
const supportedSites = ["robertsspaceindustries.com", "erkul.games", "uexcorp.space"];
|
||||
if (supportedSites.find(site => tab.url.includes(site))) {
|
||||
if (tab && tab.url && supportedSites.find(site => tab.url!.includes(site))) {
|
||||
passedUrl = tab.url;
|
||||
}
|
||||
_initLocalization(passedUrl).then(data => {
|
||||
if (tab && tab.id !== undefined) {
|
||||
chrome.tabs.sendMessage(tab.id, {action: "_toggleTranslation", data});
|
||||
}
|
||||
});
|
||||
});
|
@ -1,3 +1,6 @@
|
||||
declare const $: any;
|
||||
declare const timeago: any;
|
||||
|
||||
let SCLocalizationReplaceLocalesMap = {};
|
||||
let SCLocalizationEnableSplitMode = false;
|
||||
let SCLocalizationTranslating = false;
|
||||
@ -10,11 +13,11 @@ function InitWebLocalization() {
|
||||
}
|
||||
|
||||
function LocalizationWatchUpdate() {
|
||||
const m = window.MutationObserver || window.WebKitMutationObserver;
|
||||
const observer = new m(function (mutations, observer) {
|
||||
const m = window.MutationObserver || (window as any).WebKitMutationObserver;
|
||||
const observer = new m(function (mutations: MutationRecord[], observer: MutationObserver) {
|
||||
for (let mutationRecord of mutations) {
|
||||
for (let node of mutationRecord.addedNodes) {
|
||||
traverseElement(node);
|
||||
traverseElement(node as Element);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -56,54 +59,54 @@ function WebLocalizationUpdateReplaceWords(w) {
|
||||
async function allTranslate() {
|
||||
SCLocalizationTranslating = true;
|
||||
|
||||
async function replaceTextNode(node, parentNode) {
|
||||
async function replaceTextNode(node: Node, parentNode?: Element) {
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
// 保存原始文本内容
|
||||
const originalText = node.nodeValue;
|
||||
const originalText = node.nodeValue || '';
|
||||
const translatedText = GetSCLocalizationTranslateString(originalText);
|
||||
|
||||
// 只有当文本发生变化时才保存原始文本
|
||||
if (originalText !== translatedText) {
|
||||
if (originalText !== translatedText && parentNode) {
|
||||
const originalValue = parentNode.getAttribute('data-original-value') || "";
|
||||
parentNode.setAttribute('data-original-value', originalValue + originalText);
|
||||
node.nodeValue = translatedText;
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < node.childNodes.length; i++) {
|
||||
await replaceTextNode(node.childNodes[i], node);
|
||||
await replaceTextNode(node.childNodes[i], node as Element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await replaceTextNode(document.body);
|
||||
await replaceTextNode(document.body, document.body);
|
||||
}
|
||||
|
||||
async function undoTranslate() {
|
||||
async function undoTranslate(): Promise<{success: boolean}> {
|
||||
SCLocalizationTranslating = false;
|
||||
|
||||
document.querySelectorAll('*[data-original-value]').forEach(element => {
|
||||
element.innerText = element.getAttribute('data-original-value');
|
||||
document.querySelectorAll('*[data-original-value]').forEach((element: Element) => {
|
||||
(element as HTMLElement).innerText = element.getAttribute('data-original-value') || '';
|
||||
element.removeAttribute('data-original-value');
|
||||
});
|
||||
|
||||
// 处理输入元素
|
||||
const inputElements = document.querySelectorAll('input[type="button"], input[type="submit"], input[type="text"], input[type="password"]');
|
||||
inputElements.forEach(el => {
|
||||
inputElements.forEach((el: Element) => {
|
||||
// 尝试从 data-original-value 属性恢复原始值
|
||||
if (el.hasAttribute('data-original-value')) {
|
||||
if (el.type === 'button' || el.type === 'submit') {
|
||||
el.value = el.getAttribute('data-original-value');
|
||||
if ((el as HTMLInputElement).type === 'button' || (el as HTMLInputElement).type === 'submit') {
|
||||
(el as HTMLInputElement).value = el.getAttribute('data-original-value') || '';
|
||||
} else {
|
||||
el.placeholder = el.getAttribute('data-original-value');
|
||||
(el as HTMLInputElement).placeholder = el.getAttribute('data-original-value') || '';
|
||||
}
|
||||
el.removeAttribute('data-original-value');
|
||||
}
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
return Promise.resolve({ success: true });
|
||||
}
|
||||
|
||||
function traverseElement(el) {
|
||||
function traverseElement(el: Element) {
|
||||
if (!SCLocalizationTranslating) {
|
||||
return;
|
||||
}
|
||||
@ -121,10 +124,10 @@ function traverseElement(el) {
|
||||
if (child.nodeType === Node.TEXT_NODE) {
|
||||
translateElement(child, el);
|
||||
} else if (child.nodeType === Node.ELEMENT_NODE) {
|
||||
if (child.tagName === "INPUT") {
|
||||
if ((child as Element).tagName === "INPUT") {
|
||||
translateElement(child, el);
|
||||
} else {
|
||||
traverseElement(child, el);
|
||||
traverseElement(child as Element);
|
||||
}
|
||||
} else {
|
||||
// pass
|
||||
@ -160,14 +163,14 @@ function translateElement(el, parentNode) {
|
||||
el[k] = translatedText;
|
||||
}
|
||||
|
||||
function translateRelativeTimeEl(el) {
|
||||
const lang = (navigator.language || navigator.userLanguage);
|
||||
const datetime = $(el).attr('datetime');
|
||||
$(el).text(timeago.format(datetime, lang.replace('-', '_')));
|
||||
function translateRelativeTimeEl(el: Element) {
|
||||
const lang = (navigator.language || navigator.language);
|
||||
const datetime = ($ as any)(el).attr('datetime');
|
||||
($ as any)(el).text((timeago as any).format(datetime, lang.replace('-', '_')));
|
||||
}
|
||||
|
||||
function shouldTranslateEl(el) {
|
||||
const blockIds = [];
|
||||
function shouldTranslateEl(el: Element) {
|
||||
const blockIds: string[] = [];
|
||||
const blockClass = [
|
||||
"css-truncate" // 过滤文件目录
|
||||
];
|
||||
@ -262,7 +265,7 @@ window.addEventListener('message', async (event) => {
|
||||
|
||||
const { action } = event.data;
|
||||
|
||||
let response = { success: false };
|
||||
let response: {success: boolean, error?: string} = { success: false };
|
||||
|
||||
if (action === 'translate') {
|
||||
try {
|
||||
@ -271,13 +274,13 @@ window.addEventListener('message', async (event) => {
|
||||
WebLocalizationUpdateReplaceWords(response.result);
|
||||
});
|
||||
response = { success: true };
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
response = { success: false, error: error.message };
|
||||
}
|
||||
} else if (action === 'undoTranslate') {
|
||||
try {
|
||||
response = await undoTranslate();
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
response = { success: false, error: error.message };
|
||||
}
|
||||
}
|
2
dist/chrome/background/service_worker.js
vendored
2
dist/chrome/background/service_worker.js
vendored
@ -1 +1 @@
|
||||
(()=>{var e={},t={};function s(r){var n=t[r];if(void 0!==n)return n.exports;var o=t[r]={exports:{}};return e[r](o,o.exports,s),o.exports}s.rv=()=>"1.3.8",s.ruid="bundler=rspack@1.3.8";let r=null;async function n(){r=await a("versions.json"),console.log("Localization Version ==="),console.log(r)}async function o(e){if(console.log("url ==="+e),null==r)return await n(),o(e);let t=r,s={};e.includes("robertsspaceindustries.com")||e.includes("manual")?(s["zh-CN"]=await a("zh-CN-rsi.json",{cacheKey:"zh-CN",version:t.rsi}),s.concierge=await a("concierge.json",{cacheKey:"concierge",version:t.concierge}),s.orgs=await a("orgs.json",t.orgs),s.address=await a("addresses.json",{cacheKey:"orgs",version:t.addresses}),s.hangar=await a("hangar.json",{cacheKey:"hangar",version:t.hangar})):e.includes("uexcorp.space")?s.UEX=await a("zh-CN-uex.json",{cacheKey:"uex",version:t.uex}):e.includes("erkul.games")&&(s.DPS=await a("zh-CN-dps.json",{cacheKey:"dps",version:t.dps}));let c=[];function i(e){c.push(...function(e,t){let s=[],r=e[t];if("object"==typeof r)for(let[e,t]of Object.entries(r)){let r=e.toString().trim().toLowerCase().replace(/\xa0/g," ").replace(/\s{2,}/g," ");s.push({word:r,replacement:t.toString()})}return s}(s,e))}if(e.includes("robertsspaceindustries.com")||e.includes("manual")){if(e.startsWith("https://robertsspaceindustries.com/spectrum/community/"))return;i("zh-CN"),(e.startsWith("https://robertsspaceindustries.com/orgs")||e.startsWith("https://robertsspaceindustries.com/citizens")||e.startsWith("https://robertsspaceindustries.com/account/organization"))&&(c.push({word:"members",replacement:"名成员"}),i("orgs")),e.startsWith("https://robertsspaceindustries.com/account/addresses")&&i("address"),e.startsWith("https://robertsspaceindustries.com/account/referral-program")&&c.push({word:"Total recruits: ",replacement:"总邀请数:"},{word:"Prospects ",replacement:"未完成的邀请"},{word:"Recruits",replacement:"已完成的邀请"}),e.startsWith("https://robertsspaceindustries.com/account/concierge")&&(c=[],i("concierge")),e.startsWith("https://robertsspaceindustries.com/account/pledges")&&i("hangar")}else e.includes("uexcorp.space")?i("UEX"):e.includes("erkul.games")&&i("DPS");return c}async function a(e,{cacheKey:t="",version:s=null}={}){if(url="https://git.scbox.xkeyc.cn/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales/"+e,t&&""!==t){let e=await c(`${t}_version`),r=await c(t);if(r&&"object"==typeof r&&Object.keys(r).length>0&&e===s)return r}let r=new Date,n=await fetch(url,{method:"GET",mode:"cors"}),o=new Date,u=await n.json();return t&&""!==t&&(console.log(`update ${t} v == ${s} time == ${(o-r)/1e3}s`),await i(t,u),await i(`${t}_version`,s)),u}function c(e){return new Promise(t=>{chrome.storage.local.get([e],s=>{t(s[e]||null)})})}function i(e,t){return new Promise(s=>{let r={};r[e]=t,chrome.storage.local.set(r,()=>{s()})})}chrome.runtime.onInstalled.addListener(function(){n().then(e=>{}),console.log("SWTT init")}),chrome.runtime.onMessage.addListener(function(e,t,s){if("_loadLocalizationData"===e.action)return o(e.url).then(e=>{s({result:e})}),!0}),chrome.runtime.onInstalled.addListener(function(){chrome.contextMenus.create({id:"translate",title:"切换翻译",contexts:["page"]})}),chrome.contextMenus.onClicked.addListener((e,t)=>{console.log("contextMenus",e,t);let s="manual";["robertsspaceindustries.com","erkul.games","uexcorp.space"].find(e=>t.url.includes(e))&&(s=t.url),o(s).then(e=>{chrome.tabs.sendMessage(t.id,{action:"_toggleTranslation",data:e})})})})();
|
||||
(()=>{var e={},t={};function s(r){var n=t[r];if(void 0!==n)return n.exports;var o=t[r]={exports:{}};return e[r](o,o.exports,s),o.exports}s.rv=()=>"1.3.8",s.ruid="bundler=rspack@1.3.8";let r=null;async function n(){r=await a("versions.json"),console.log("Localization Version ==="),console.log(r)}async function o(e){if(console.log("url ==="+e),null==r)return await n(),o(e);let t=r,s={};e.includes("robertsspaceindustries.com")||e.includes("manual")?(s["zh-CN"]=await a("zh-CN-rsi.json",{cacheKey:"zh-CN",version:t.rsi}),s.concierge=await a("concierge.json",{cacheKey:"concierge",version:t.concierge}),s.orgs=await a("orgs.json",{cacheKey:"orgs",version:t.orgs}),s.address=await a("addresses.json",{cacheKey:"orgs",version:t.addresses}),s.hangar=await a("hangar.json",{cacheKey:"hangar",version:t.hangar})):e.includes("uexcorp.space")?s.UEX=await a("zh-CN-uex.json",{cacheKey:"uex",version:t.uex}):e.includes("erkul.games")&&(s.DPS=await a("zh-CN-dps.json",{cacheKey:"dps",version:t.dps}));let c=[];function i(e){c.push(...function(e,t){let s=[],r=e[t];if("object"==typeof r)for(let[e,t]of Object.entries(r)){let r=e.toString().trim().toLowerCase().replace(/\xa0/g," ").replace(/\s{2,}/g," ");s.push({word:r,replacement:String(t)})}return s}(s,e))}if(e.includes("robertsspaceindustries.com")||e.includes("manual")){if(e.startsWith("https://robertsspaceindustries.com/spectrum/community/"))return[];i("zh-CN"),(e.startsWith("https://robertsspaceindustries.com/orgs")||e.startsWith("https://robertsspaceindustries.com/citizens")||e.startsWith("https://robertsspaceindustries.com/account/organization"))&&(c.push({word:"members",replacement:"名成员"}),i("orgs")),e.startsWith("https://robertsspaceindustries.com/account/addresses")&&i("address"),e.startsWith("https://robertsspaceindustries.com/account/referral-program")&&c.push({word:"Total recruits: ",replacement:"总邀请数:"},{word:"Prospects ",replacement:"未完成的邀请"},{word:"Recruits",replacement:"已完成的邀请"}),e.startsWith("https://robertsspaceindustries.com/account/concierge")&&(c=[],i("concierge")),e.startsWith("https://robertsspaceindustries.com/account/pledges")&&i("hangar")}else e.includes("uexcorp.space")?i("UEX"):e.includes("erkul.games")&&i("DPS");return c}async function a(e,t={}){let{cacheKey:s="",version:r=null}=t;if(s&&""!==s){let e=await c(`${s}_version`),t=await c(s);if(t&&"object"==typeof t&&Object.keys(t).length>0&&e===r)return t}let n=new Date,o=await fetch("https://git.scbox.xkeyc.cn/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales/"+e,{method:"GET",mode:"cors"}),l=new Date,u=await o.json();if(s&&""!==s){let e=l.getTime()-n.getTime();console.log(`update ${s} v == ${r} time == ${e/1e3}s`),await i(s,u),await i(`${s}_version`,r)}return u}function c(e){return new Promise(t=>{chrome.storage.local.get([e],s=>{t(s[e]||null)})})}function i(e,t){return new Promise(s=>{let r={};r[e]=t,chrome.storage.local.set(r,()=>{s()})})}chrome.runtime.onInstalled.addListener(function(){n().then(e=>{}),console.log("SWTT init")}),chrome.runtime.onMessage.addListener(function(e,t,s){if("_loadLocalizationData"===e.action)return o(e.url).then(e=>{s({result:e})}),!0}),chrome.runtime.onInstalled.addListener(function(){chrome.contextMenus.create({id:"translate",title:"切换翻译",contexts:["all"]})}),chrome.contextMenus.onClicked.addListener((e,t)=>{console.log("contextMenus",e,t);let s="manual";t&&t.url&&["robertsspaceindustries.com","erkul.games","uexcorp.space"].find(e=>t.url.includes(e))&&(s=t.url),o(s).then(e=>{t&&void 0!==t.id&&chrome.tabs.sendMessage(t.id,{action:"_toggleTranslation",data:e})})})})();
|
2
dist/chrome/content_scripts/content-0.js
vendored
2
dist/chrome/content_scripts/content-0.js
vendored
File diff suppressed because one or more lines are too long
2
dist/chrome/content_scripts/content-1.js
vendored
2
dist/chrome/content_scripts/content-1.js
vendored
File diff suppressed because one or more lines are too long
2
dist/chrome/content_scripts/content-2.js
vendored
2
dist/chrome/content_scripts/content-2.js
vendored
@ -1 +1 @@
|
||||
(()=>{var e={},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var a=t[n]={exports:{}};return e[n](a,a.exports,r),a.exports}r.rv=()=>"1.3.8",r.ruid="bundler=rspack@1.3.8",function(){function e(t,r,n,o=100){let a=setInterval(()=>{let e=t.querySelector(r);e&&(clearInterval(a),n(e))},o)}function t(e){if(!e||e.parentNode.querySelector('a[data-cy-id="button"][href="/account/pledges"]'))return;let t=e.cloneNode(!0);t.href="/account/pledges";let r=t.querySelector('span[data-cy-id="button__text"]');r&&(r.innerText="My Hangar");let n=t.querySelector('i[data-cy-id="button__icon"]');n&&(n.className="a-button__icon a-icon -gridView"),e.parentNode.insertBefore(t,e)}e(document,"#sidePanel",r=>{new MutationObserver(r=>{for(let n of r)"childList"===n.type&&n.addedNodes.length>0&&n.addedNodes.forEach(r=>{1===r.nodeType&&e(r,'a[data-cy-id="button"][href="/account/settings"]',e=>{t(e)})})}).observe(r,{childList:!0,subtree:!0});let n=sidePanel.querySelector('a[data-cy-id="button"][href="/account/settings"]');n&&t(n)})}()})();
|
||||
(()=>{var e={},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var a=t[n]={exports:{}};return e[n](a,a.exports,r),a.exports}r.rv=()=>"1.3.8",r.ruid="bundler=rspack@1.3.8",function(){function e(t,r,n,o=100){let a=setInterval(()=>{let e=t.querySelector(r);e&&(clearInterval(a),n(e))},o)}function t(e){if(!e||e.parentNode.querySelector('a[data-cy-id="button"][href="/account/pledges"]'))return;let t=e.cloneNode(!0);t.href="/account/pledges";let r=t.querySelector('span[data-cy-id="button__text"]');r&&(r.innerText="My Hangar");let n=t.querySelector('i[data-cy-id="button__icon"]');n&&(n.className="a-button__icon a-icon -gridView"),e.parentNode.insertBefore(t,e)}e(document,"#sidePanel",r=>{new MutationObserver(r=>{for(let n of r)"childList"===n.type&&n.addedNodes.length>0&&n.addedNodes.forEach(r=>{1===r.nodeType&&e(r,'a[data-cy-id="button"][href="/account/settings"]',e=>{t(e)})})}).observe(r,{childList:!0,subtree:!0});let n=r.querySelector('a[data-cy-id="button"][href="/account/settings"]');n&&t(n)})}()})();
|
2
dist/firefox/background/scripts.js
vendored
2
dist/firefox/background/scripts.js
vendored
@ -1 +1 @@
|
||||
(()=>{var e={},t={};function s(r){var n=t[r];if(void 0!==n)return n.exports;var o=t[r]={exports:{}};return e[r](o,o.exports,s),o.exports}s.rv=()=>"1.3.8",s.ruid="bundler=rspack@1.3.8";let r=null;async function n(){r=await a("versions.json"),console.log("Localization Version ==="),console.log(r)}async function o(e){if(console.log("url ==="+e),null==r)return await n(),o(e);let t=r,s={};e.includes("robertsspaceindustries.com")||e.includes("manual")?(s["zh-CN"]=await a("zh-CN-rsi.json",{cacheKey:"zh-CN",version:t.rsi}),s.concierge=await a("concierge.json",{cacheKey:"concierge",version:t.concierge}),s.orgs=await a("orgs.json",t.orgs),s.address=await a("addresses.json",{cacheKey:"orgs",version:t.addresses}),s.hangar=await a("hangar.json",{cacheKey:"hangar",version:t.hangar})):e.includes("uexcorp.space")?s.UEX=await a("zh-CN-uex.json",{cacheKey:"uex",version:t.uex}):e.includes("erkul.games")&&(s.DPS=await a("zh-CN-dps.json",{cacheKey:"dps",version:t.dps}));let c=[];function i(e){c.push(...function(e,t){let s=[],r=e[t];if("object"==typeof r)for(let[e,t]of Object.entries(r)){let r=e.toString().trim().toLowerCase().replace(/\xa0/g," ").replace(/\s{2,}/g," ");s.push({word:r,replacement:t.toString()})}return s}(s,e))}if(e.includes("robertsspaceindustries.com")||e.includes("manual")){if(e.startsWith("https://robertsspaceindustries.com/spectrum/community/"))return;i("zh-CN"),(e.startsWith("https://robertsspaceindustries.com/orgs")||e.startsWith("https://robertsspaceindustries.com/citizens")||e.startsWith("https://robertsspaceindustries.com/account/organization"))&&(c.push({word:"members",replacement:"名成员"}),i("orgs")),e.startsWith("https://robertsspaceindustries.com/account/addresses")&&i("address"),e.startsWith("https://robertsspaceindustries.com/account/referral-program")&&c.push({word:"Total recruits: ",replacement:"总邀请数:"},{word:"Prospects ",replacement:"未完成的邀请"},{word:"Recruits",replacement:"已完成的邀请"}),e.startsWith("https://robertsspaceindustries.com/account/concierge")&&(c=[],i("concierge")),e.startsWith("https://robertsspaceindustries.com/account/pledges")&&i("hangar")}else e.includes("uexcorp.space")?i("UEX"):e.includes("erkul.games")&&i("DPS");return c}async function a(e,{cacheKey:t="",version:s=null}={}){if(url="https://git.scbox.xkeyc.cn/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales/"+e,t&&""!==t){let e=await c(`${t}_version`),r=await c(t);if(r&&"object"==typeof r&&Object.keys(r).length>0&&e===s)return r}let r=new Date,n=await fetch(url,{method:"GET",mode:"cors"}),o=new Date,u=await n.json();return t&&""!==t&&(console.log(`update ${t} v == ${s} time == ${(o-r)/1e3}s`),await i(t,u),await i(`${t}_version`,s)),u}function c(e){return new Promise(t=>{chrome.storage.local.get([e],s=>{t(s[e]||null)})})}function i(e,t){return new Promise(s=>{let r={};r[e]=t,chrome.storage.local.set(r,()=>{s()})})}chrome.runtime.onInstalled.addListener(function(){n().then(e=>{}),console.log("SWTT init")}),chrome.runtime.onMessage.addListener(function(e,t,s){if("_loadLocalizationData"===e.action)return o(e.url).then(e=>{s({result:e})}),!0}),chrome.runtime.onInstalled.addListener(function(){chrome.contextMenus.create({id:"translate",title:"切换翻译",contexts:["page"]})}),chrome.contextMenus.onClicked.addListener((e,t)=>{console.log("contextMenus",e,t);let s="manual";["robertsspaceindustries.com","erkul.games","uexcorp.space"].find(e=>t.url.includes(e))&&(s=t.url),o(s).then(e=>{chrome.tabs.sendMessage(t.id,{action:"_toggleTranslation",data:e})})})})();
|
||||
(()=>{var e={},t={};function s(r){var n=t[r];if(void 0!==n)return n.exports;var o=t[r]={exports:{}};return e[r](o,o.exports,s),o.exports}s.rv=()=>"1.3.8",s.ruid="bundler=rspack@1.3.8";let r=null;async function n(){r=await a("versions.json"),console.log("Localization Version ==="),console.log(r)}async function o(e){if(console.log("url ==="+e),null==r)return await n(),o(e);let t=r,s={};e.includes("robertsspaceindustries.com")||e.includes("manual")?(s["zh-CN"]=await a("zh-CN-rsi.json",{cacheKey:"zh-CN",version:t.rsi}),s.concierge=await a("concierge.json",{cacheKey:"concierge",version:t.concierge}),s.orgs=await a("orgs.json",{cacheKey:"orgs",version:t.orgs}),s.address=await a("addresses.json",{cacheKey:"orgs",version:t.addresses}),s.hangar=await a("hangar.json",{cacheKey:"hangar",version:t.hangar})):e.includes("uexcorp.space")?s.UEX=await a("zh-CN-uex.json",{cacheKey:"uex",version:t.uex}):e.includes("erkul.games")&&(s.DPS=await a("zh-CN-dps.json",{cacheKey:"dps",version:t.dps}));let c=[];function i(e){c.push(...function(e,t){let s=[],r=e[t];if("object"==typeof r)for(let[e,t]of Object.entries(r)){let r=e.toString().trim().toLowerCase().replace(/\xa0/g," ").replace(/\s{2,}/g," ");s.push({word:r,replacement:String(t)})}return s}(s,e))}if(e.includes("robertsspaceindustries.com")||e.includes("manual")){if(e.startsWith("https://robertsspaceindustries.com/spectrum/community/"))return[];i("zh-CN"),(e.startsWith("https://robertsspaceindustries.com/orgs")||e.startsWith("https://robertsspaceindustries.com/citizens")||e.startsWith("https://robertsspaceindustries.com/account/organization"))&&(c.push({word:"members",replacement:"名成员"}),i("orgs")),e.startsWith("https://robertsspaceindustries.com/account/addresses")&&i("address"),e.startsWith("https://robertsspaceindustries.com/account/referral-program")&&c.push({word:"Total recruits: ",replacement:"总邀请数:"},{word:"Prospects ",replacement:"未完成的邀请"},{word:"Recruits",replacement:"已完成的邀请"}),e.startsWith("https://robertsspaceindustries.com/account/concierge")&&(c=[],i("concierge")),e.startsWith("https://robertsspaceindustries.com/account/pledges")&&i("hangar")}else e.includes("uexcorp.space")?i("UEX"):e.includes("erkul.games")&&i("DPS");return c}async function a(e,t={}){let{cacheKey:s="",version:r=null}=t;if(s&&""!==s){let e=await c(`${s}_version`),t=await c(s);if(t&&"object"==typeof t&&Object.keys(t).length>0&&e===r)return t}let n=new Date,o=await fetch("https://git.scbox.xkeyc.cn/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales/"+e,{method:"GET",mode:"cors"}),l=new Date,u=await o.json();if(s&&""!==s){let e=l.getTime()-n.getTime();console.log(`update ${s} v == ${r} time == ${e/1e3}s`),await i(s,u),await i(`${s}_version`,r)}return u}function c(e){return new Promise(t=>{chrome.storage.local.get([e],s=>{t(s[e]||null)})})}function i(e,t){return new Promise(s=>{let r={};r[e]=t,chrome.storage.local.set(r,()=>{s()})})}chrome.runtime.onInstalled.addListener(function(){n().then(e=>{}),console.log("SWTT init")}),chrome.runtime.onMessage.addListener(function(e,t,s){if("_loadLocalizationData"===e.action)return o(e.url).then(e=>{s({result:e})}),!0}),chrome.runtime.onInstalled.addListener(function(){chrome.contextMenus.create({id:"translate",title:"切换翻译",contexts:["all"]})}),chrome.contextMenus.onClicked.addListener((e,t)=>{console.log("contextMenus",e,t);let s="manual";t&&t.url&&["robertsspaceindustries.com","erkul.games","uexcorp.space"].find(e=>t.url.includes(e))&&(s=t.url),o(s).then(e=>{t&&void 0!==t.id&&chrome.tabs.sendMessage(t.id,{action:"_toggleTranslation",data:e})})})})();
|
2
dist/firefox/content_scripts/content-0.js
vendored
2
dist/firefox/content_scripts/content-0.js
vendored
File diff suppressed because one or more lines are too long
2
dist/firefox/content_scripts/content-1.js
vendored
2
dist/firefox/content_scripts/content-1.js
vendored
File diff suppressed because one or more lines are too long
2
dist/firefox/content_scripts/content-2.js
vendored
2
dist/firefox/content_scripts/content-2.js
vendored
@ -1 +1 @@
|
||||
(()=>{var e={},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var a=t[n]={exports:{}};return e[n](a,a.exports,r),a.exports}r.rv=()=>"1.3.8",r.ruid="bundler=rspack@1.3.8",function(){function e(t,r,n,o=100){let a=setInterval(()=>{let e=t.querySelector(r);e&&(clearInterval(a),n(e))},o)}function t(e){if(!e||e.parentNode.querySelector('a[data-cy-id="button"][href="/account/pledges"]'))return;let t=e.cloneNode(!0);t.href="/account/pledges";let r=t.querySelector('span[data-cy-id="button__text"]');r&&(r.innerText="My Hangar");let n=t.querySelector('i[data-cy-id="button__icon"]');n&&(n.className="a-button__icon a-icon -gridView"),e.parentNode.insertBefore(t,e)}e(document,"#sidePanel",r=>{new MutationObserver(r=>{for(let n of r)"childList"===n.type&&n.addedNodes.length>0&&n.addedNodes.forEach(r=>{1===r.nodeType&&e(r,'a[data-cy-id="button"][href="/account/settings"]',e=>{t(e)})})}).observe(r,{childList:!0,subtree:!0});let n=sidePanel.querySelector('a[data-cy-id="button"][href="/account/settings"]');n&&t(n)})}()})();
|
||||
(()=>{var e={},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var a=t[n]={exports:{}};return e[n](a,a.exports,r),a.exports}r.rv=()=>"1.3.8",r.ruid="bundler=rspack@1.3.8",function(){function e(t,r,n,o=100){let a=setInterval(()=>{let e=t.querySelector(r);e&&(clearInterval(a),n(e))},o)}function t(e){if(!e||e.parentNode.querySelector('a[data-cy-id="button"][href="/account/pledges"]'))return;let t=e.cloneNode(!0);t.href="/account/pledges";let r=t.querySelector('span[data-cy-id="button__text"]');r&&(r.innerText="My Hangar");let n=t.querySelector('i[data-cy-id="button__icon"]');n&&(n.className="a-button__icon a-icon -gridView"),e.parentNode.insertBefore(t,e)}e(document,"#sidePanel",r=>{new MutationObserver(r=>{for(let n of r)"childList"===n.type&&n.addedNodes.length>0&&n.addedNodes.forEach(r=>{1===r.nodeType&&e(r,'a[data-cy-id="button"][href="/account/settings"]',e=>{t(e)})})}).observe(r,{childList:!0,subtree:!0});let n=r.querySelector('a[data-cy-id="button"][href="/account/settings"]');n&&t(n)})}()})();
|
@ -21,8 +21,8 @@
|
||||
"default_popup": "popup.html"
|
||||
},
|
||||
"background": {
|
||||
"chromium:service_worker": "background.js",
|
||||
"firefox:scripts": ["background.js"]
|
||||
"chromium:service_worker": "background.ts",
|
||||
"firefox:scripts": ["background.ts"]
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
@ -33,7 +33,7 @@
|
||||
"https://robertsspaceindustries.com/spectrum/*"
|
||||
],
|
||||
"js": [
|
||||
"core.js",
|
||||
"core.ts",
|
||||
"thirdparty/timeago.full.min.js"
|
||||
],
|
||||
"run_at": "document_end"
|
||||
@ -52,7 +52,7 @@
|
||||
"https://robertsspaceindustries.com/*"
|
||||
],
|
||||
"js": [
|
||||
"rsi_hangar_fix.js"
|
||||
"rsi_hangar_fix.ts"
|
||||
],
|
||||
"run_at": "document_idle"
|
||||
}
|
||||
|
@ -21,7 +21,9 @@
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"extension": "^2.0.0-rc.23"
|
||||
"extension": "^2.0.0-rc.23",
|
||||
"@types/node": "^22.10.5",
|
||||
"typescript": "5.3.3"
|
||||
},
|
||||
"private": true,
|
||||
"author": {
|
||||
|
36
pnpm-lock.yaml
generated
36
pnpm-lock.yaml
generated
@ -8,9 +8,15 @@ importers:
|
||||
|
||||
.:
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
specifier: ^22.10.5
|
||||
version: 22.15.3
|
||||
extension:
|
||||
specifier: ^2.0.0-rc.23
|
||||
version: 2.0.0-rc.23(@babel/core@7.27.1)(@prefresh/babel-plugin@0.5.1)(@types/express@4.17.21)(less@4.3.0)(svelte@5.28.2)(webpack@5.99.7)
|
||||
version: 2.0.0-rc.23(@babel/core@7.27.1)(@prefresh/babel-plugin@0.5.1)(@types/express@4.17.21)(less@4.3.0)(svelte@5.28.2)(typescript@5.3.3)(webpack@5.99.7)
|
||||
typescript:
|
||||
specifier: 5.3.3
|
||||
version: 5.3.3
|
||||
|
||||
packages:
|
||||
|
||||
@ -2290,6 +2296,11 @@ packages:
|
||||
typedarray@0.0.6:
|
||||
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
|
||||
|
||||
typescript@5.3.3:
|
||||
resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
@ -3542,12 +3553,14 @@ snapshots:
|
||||
|
||||
core-util-is@1.0.3: {}
|
||||
|
||||
cosmiconfig@9.0.0:
|
||||
cosmiconfig@9.0.0(typescript@5.3.3):
|
||||
dependencies:
|
||||
env-paths: 2.2.1
|
||||
import-fresh: 3.3.1
|
||||
js-yaml: 4.1.0
|
||||
parse-json: 5.2.0
|
||||
optionalDependencies:
|
||||
typescript: 5.3.3
|
||||
optional: true
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
@ -3779,7 +3792,7 @@ snapshots:
|
||||
go-git-it: 2.0.4
|
||||
package-manager-detector: 0.2.11
|
||||
|
||||
extension-develop@2.0.0-rc.23(@babel/core@7.27.1)(@prefresh/babel-plugin@0.5.1)(@types/express@4.17.21)(less@4.3.0)(svelte@5.28.2)(webpack@5.99.7):
|
||||
extension-develop@2.0.0-rc.23(@babel/core@7.27.1)(@prefresh/babel-plugin@0.5.1)(@types/express@4.17.21)(less@4.3.0)(svelte@5.28.2)(typescript@5.3.3)(webpack@5.99.7):
|
||||
dependencies:
|
||||
'@colors/colors': 1.6.0
|
||||
'@rspack/core': 1.3.8(@swc/helpers@0.5.17)
|
||||
@ -3826,12 +3839,12 @@ snapshots:
|
||||
'@rspack/plugin-react-refresh': 1.4.1(react-refresh@0.14.2)
|
||||
babel-loader: 9.2.1(@babel/core@7.27.1)(webpack@5.99.7)
|
||||
less-loader: 12.3.0(@rspack/core@1.3.8(@swc/helpers@0.5.17))(less@4.3.0)(webpack@5.99.7)
|
||||
postcss-loader: 8.1.1(@rspack/core@1.3.8(@swc/helpers@0.5.17))(postcss@8.5.3)(webpack@5.99.7)
|
||||
postcss-loader: 8.1.1(@rspack/core@1.3.8(@swc/helpers@0.5.17))(postcss@8.5.3)(typescript@5.3.3)(webpack@5.99.7)
|
||||
postcss-preset-env: 10.1.6(postcss@8.5.3)
|
||||
react-refresh: 0.14.2
|
||||
sass-loader: 16.0.5(@rspack/core@1.3.8(@swc/helpers@0.5.17))(webpack@5.99.7)
|
||||
svelte-loader: 3.2.4(svelte@5.28.2)
|
||||
svelte-preprocess: 6.0.3(@babel/core@7.27.1)(less@4.3.0)(postcss@8.5.3)(svelte@5.28.2)
|
||||
svelte-preprocess: 6.0.3(@babel/core@7.27.1)(less@4.3.0)(postcss@8.5.3)(svelte@5.28.2)(typescript@5.3.3)
|
||||
vue-loader: 17.4.2(@vue/compiler-sfc@3.5.13)(webpack@5.99.7)
|
||||
vue-style-loader: 4.1.3
|
||||
vue-template-compiler: 2.7.16
|
||||
@ -3859,7 +3872,7 @@ snapshots:
|
||||
- webpack-cli
|
||||
- webpack-hot-middleware
|
||||
|
||||
extension@2.0.0-rc.23(@babel/core@7.27.1)(@prefresh/babel-plugin@0.5.1)(@types/express@4.17.21)(less@4.3.0)(svelte@5.28.2)(webpack@5.99.7):
|
||||
extension@2.0.0-rc.23(@babel/core@7.27.1)(@prefresh/babel-plugin@0.5.1)(@types/express@4.17.21)(less@4.3.0)(svelte@5.28.2)(typescript@5.3.3)(webpack@5.99.7):
|
||||
dependencies:
|
||||
'@colors/colors': 1.6.0
|
||||
'@types/chrome': 0.0.287
|
||||
@ -3869,7 +3882,7 @@ snapshots:
|
||||
'@types/react-dom': 19.1.3(@types/react@19.1.2)
|
||||
commander: 12.1.0
|
||||
extension-create: 2.0.1
|
||||
extension-develop: 2.0.0-rc.23(@babel/core@7.27.1)(@prefresh/babel-plugin@0.5.1)(@types/express@4.17.21)(less@4.3.0)(svelte@5.28.2)(webpack@5.99.7)
|
||||
extension-develop: 2.0.0-rc.23(@babel/core@7.27.1)(@prefresh/babel-plugin@0.5.1)(@types/express@4.17.21)(less@4.3.0)(svelte@5.28.2)(typescript@5.3.3)(webpack@5.99.7)
|
||||
semver: 7.7.1
|
||||
update-check: 1.5.4
|
||||
webextension-polyfill: 0.12.0
|
||||
@ -4570,9 +4583,9 @@ snapshots:
|
||||
postcss: 8.5.3
|
||||
optional: true
|
||||
|
||||
postcss-loader@8.1.1(@rspack/core@1.3.8(@swc/helpers@0.5.17))(postcss@8.5.3)(webpack@5.99.7):
|
||||
postcss-loader@8.1.1(@rspack/core@1.3.8(@swc/helpers@0.5.17))(postcss@8.5.3)(typescript@5.3.3)(webpack@5.99.7):
|
||||
dependencies:
|
||||
cosmiconfig: 9.0.0
|
||||
cosmiconfig: 9.0.0(typescript@5.3.3)
|
||||
jiti: 1.21.7
|
||||
postcss: 8.5.3
|
||||
semver: 7.7.1
|
||||
@ -5018,13 +5031,14 @@ snapshots:
|
||||
svelte-hmr: 0.14.12(svelte@5.28.2)
|
||||
optional: true
|
||||
|
||||
svelte-preprocess@6.0.3(@babel/core@7.27.1)(less@4.3.0)(postcss@8.5.3)(svelte@5.28.2):
|
||||
svelte-preprocess@6.0.3(@babel/core@7.27.1)(less@4.3.0)(postcss@8.5.3)(svelte@5.28.2)(typescript@5.3.3):
|
||||
dependencies:
|
||||
svelte: 5.28.2
|
||||
optionalDependencies:
|
||||
'@babel/core': 7.27.1
|
||||
less: 4.3.0
|
||||
postcss: 8.5.3
|
||||
typescript: 5.3.3
|
||||
optional: true
|
||||
|
||||
svelte@5.28.2:
|
||||
@ -5093,6 +5107,8 @@ snapshots:
|
||||
|
||||
typedarray@0.0.6: {}
|
||||
|
||||
typescript@5.3.3: {}
|
||||
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
universalify@2.0.1: {}
|
||||
|
@ -1,93 +0,0 @@
|
||||
// from https://github.com/cfdxkk/RSI-Hangar-Button
|
||||
// LICENSE GLWT(Good Luck With That) Public License
|
||||
(function () {
|
||||
/**
|
||||
* 寻找元素直到元素被加载
|
||||
* @param dom 查找的根元素
|
||||
* @param selector 元素的查找
|
||||
* @param callback 查找到的回调
|
||||
* @param interval 查找的间隔,默认 100 毫秒
|
||||
*/
|
||||
function waitForElement(dom, selector, callback, interval = 100) {
|
||||
const checkExist = setInterval(() => {
|
||||
const element = dom.querySelector(selector)
|
||||
if (element) {
|
||||
clearInterval(checkExist) // 停止轮询
|
||||
callback(element)
|
||||
}
|
||||
}, interval)
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始监听抽屉,如果监听到点击事件,则添加按钮
|
||||
* @param element
|
||||
*/
|
||||
function startObserve(element) {
|
||||
// 创建一个 MutationObserver 实例,监听元素的子元素变化
|
||||
const observer = new MutationObserver((mutationsList) => {
|
||||
for (const mutation of mutationsList) {
|
||||
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
|
||||
mutation.addedNodes.forEach(node => {
|
||||
if (node.nodeType === 1) { // 只处理元素节点 (忽略文本节点)
|
||||
waitForElement(node, "a[data-cy-id=\"button\"][href=\"/account/settings\"]", (button) => {
|
||||
copyAndAddButton(button)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 监听子节点变化,并对子树内的变化也进行监听
|
||||
observer.observe(element, { childList: true, subtree: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制原有按钮,将其修改为机库按钮并插入到原按钮的上方
|
||||
* 在插入前先检查是否已经存在对应的按钮
|
||||
* @param {HTMLElement} button 原始按钮
|
||||
*/
|
||||
function copyAndAddButton(button) {
|
||||
if (!button) return
|
||||
|
||||
// 如果已经存在 href 为 /account/pledges 的按钮,则不再添加
|
||||
if (button.parentNode.querySelector('a[data-cy-id="button"][href="/account/pledges"]')) {
|
||||
return
|
||||
}
|
||||
// 复制元素
|
||||
const hangarButton = button.cloneNode(true)
|
||||
|
||||
// 修改 href
|
||||
hangarButton.href = "/account/pledges"
|
||||
|
||||
// 查找按钮中的文本部分
|
||||
const hangarButtonText = hangarButton.querySelector('span[data-cy-id="button__text"]')
|
||||
|
||||
// 修改文本
|
||||
if (hangarButtonText) {
|
||||
hangarButtonText.innerText = "My Hangar"
|
||||
}
|
||||
|
||||
// 查找按钮中的图标部分
|
||||
const hangarButtonIcon = hangarButton.querySelector('i[data-cy-id="button__icon"]')
|
||||
|
||||
// 修改图标
|
||||
if (hangarButtonIcon) {
|
||||
hangarButtonIcon.className = "a-button__icon a-icon -gridView"
|
||||
}
|
||||
|
||||
// 插入到目标元素的前方
|
||||
button.parentNode.insertBefore(hangarButton, button)
|
||||
}
|
||||
|
||||
// 开始查找抽屉,如果找到执行监听回调
|
||||
waitForElement(document, "#sidePanel", (risSidePanel) => {
|
||||
startObserve(risSidePanel)
|
||||
|
||||
// 初始检查:防止首次打开抽屉时按钮已经存在,MutationObserver 不触发
|
||||
const button = sidePanel.querySelector('a[data-cy-id="button"][href="/account/settings"]')
|
||||
if (button) {
|
||||
copyAndAddButton(button)
|
||||
}
|
||||
})
|
||||
})()
|
@ -81,11 +81,11 @@
|
||||
}
|
||||
|
||||
// 开始查找抽屉,如果找到执行监听回调
|
||||
waitForElement(document, "#sidePanel", (risSidePanel) => {
|
||||
startObserve(risSidePanel)
|
||||
waitForElement(document, "#sidePanel", (rsiSidePanel) => {
|
||||
startObserve(rsiSidePanel)
|
||||
|
||||
// 初始检查:防止首次打开抽屉时按钮已经存在,MutationObserver 不触发
|
||||
const button = sidePanel.querySelector('a[data-cy-id="button"][href="/account/settings"]')
|
||||
const button = rsiSidePanel.querySelector('a[data-cy-id="button"][href="/account/settings"]')
|
||||
if (button) {
|
||||
copyAndAddButton(button)
|
||||
}
|
25
tsconfig.json
Normal file
25
tsconfig.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"isolatedModules": true,
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"moduleResolution": "node",
|
||||
"module": "esnext",
|
||||
"noEmit": true,
|
||||
"resolveJsonModule": true,
|
||||
"strict": true,
|
||||
"target": "esnext",
|
||||
"verbatimModuleSyntax": true,
|
||||
"useDefineForClassFields": true,
|
||||
"skipLibCheck": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": ["./"],
|
||||
"exclude": ["node_modules", "dist"],
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user