diff --git a/global.d.ts b/global.d.ts index 9e07817..cb1ce1d 100644 --- a/global.d.ts +++ b/global.d.ts @@ -1,5 +1,11 @@ declare interface String { contains(keywords: RegExp | string): boolean; + + /* 翻译 */ + // 时分秒转换 + replaceHMS(): string; + // 数词转换 a an some + numWordTrans(): string; } declare interface Window { diff --git a/src/func/translate/contentTitleLinksTrans.ts b/src/func/translate/contentTitleLinksTrans.ts new file mode 100644 index 0000000..b62cc32 --- /dev/null +++ b/src/func/translate/contentTitleLinksTrans.ts @@ -0,0 +1,21 @@ +import {titleLinksDict} from "../../dictionary/translation"; + +// 页标题右侧按钮 +export default function contentTitleLinksTrans() { + const $links_default = document.querySelectorAll('div.content-title span:nth-child(2)'); + const $links = $links_default.length === 0 + ? document.querySelectorAll('div[class^="topSection"] span[class*="Title"]') + : $links_default; + $links.forEach(e => { + if (titleLinksDict[e.innerText.trim()]) { + e.innerText = titleLinksDict[e.innerText.trim()]; + } else if (e.id === 'events') { + if (titleLinksDict[e.innerText.trim().split(' ')[0]]) + e.innerText = e.innerText.trim() + .replace( + e.innerText.trim().split(' ')[0], + titleLinksDict[e.innerText.trim().split(' ')[0]] + ); + } + }); +} \ No newline at end of file diff --git a/src/func/translate/contentTitleLinksTransReact.ts b/src/func/translate/contentTitleLinksTransReact.ts new file mode 100644 index 0000000..0cff4d0 --- /dev/null +++ b/src/func/translate/contentTitleLinksTransReact.ts @@ -0,0 +1,8 @@ +import {titleLinksDict} from "../../dictionary/translation"; + +export default function contentTitleLinksTransReact(dom = document.querySelectorAll('div[class^="linksContainer___"] span[class^="linkTitle___"]')) { + dom.forEach(e => { + const links_trans = titleLinksDict[e.innerText.trim()]; + if (links_trans) e.innerText = links_trans; + }); +} \ No newline at end of file diff --git a/src/func/translate/initOB.ts b/src/func/translate/initOB.ts new file mode 100644 index 0000000..75506b1 --- /dev/null +++ b/src/func/translate/initOB.ts @@ -0,0 +1,32 @@ +/** + * ob + * @deprecated TODO 泛用模版有性能问题 + */ +import log from "../utils/log"; + +export default function initOB(dom: Document | Element = document, opt = {}, func = () => { +}, dev = false, once = false) { + //let count = -1; + if (dev) { + const mo = new MutationObserver((mutation) => { + //count++; + log.info(mutation) + mo.disconnect(); + func(); + if (!once) { + mo.observe(dom, opt) + } + }); + func(); + mo.observe(dom, opt); + } else { + //count++; + const mo = new MutationObserver(() => { + mo.disconnect(); + func(); + if (!once) mo.observe(dom, opt) + }); + func(); + mo.observe(dom, opt) + } +} diff --git a/src/func/translate/showItemInfoTrans.ts b/src/func/translate/showItemInfoTrans.ts new file mode 100644 index 0000000..7e5a67f --- /dev/null +++ b/src/func/translate/showItemInfoTrans.ts @@ -0,0 +1,39 @@ +import {itemEffectDict, itemNameDict, itemPageDict, itemTypeDict} from "../../dictionary/translation"; + +// 展开物品详情 +export default function showItemInfoTrans(dom: HTMLElement = document.querySelector('.show-item-info')) { + if (dom) { + const $item_info = dom.querySelector('span.info-msg'); + if ($item_info) { + // tt插件 + const is_tt_modified = !!$item_info.querySelector('.tt-modified'); + if (is_tt_modified) { + console.warn(is_tt_modified) + } + // 物品名 + const $item_name = $item_info.querySelector('span.bold'); + // 去除物品名的the + const the_removed = $item_name.innerText.trim().slice(4); + // 物品的类别 + const $item_type = $item_name.nextSibling; + // 绿字 物品效果 + const $item_effect = $item_info.querySelector('div.item-effect'); + if (itemNameDict[the_removed]) { + $item_name.innerText = `${itemNameDict[the_removed]}(${the_removed})`; + } + if (itemTypeDict[$item_type.nodeValue.trim()]) { + $item_type.nodeValue = itemTypeDict[$item_type.nodeValue.trim()]; + } + if ($item_effect && itemEffectDict[$item_effect.innerText.trim()]) { + $item_effect.innerText = itemEffectDict[$item_effect.innerText.trim()]; + } + } + // 下方的表格 + const $info_table_title = dom.querySelectorAll('div.title'); + $info_table_title.forEach((e) => { + if (itemPageDict[e.innerText.trim()]) { + e.innerText = itemPageDict[e.innerText.trim()]; + } + }); + } +} \ No newline at end of file diff --git a/src/func/translate/titleTrans.ts b/src/func/translate/titleTrans.ts new file mode 100644 index 0000000..c334589 --- /dev/null +++ b/src/func/translate/titleTrans.ts @@ -0,0 +1,12 @@ +import {cityDict, titleDict} from "../../dictionary/translation"; + +/** + * 页标题翻译 + */ +export default function titleTrans() { + let node = $('h4#skip-to-content'); + const $title = node.length === 0 ? $('h4[class^="title"]') : node; + const title = titleDict[$title.text().trim()] || cityDict[$title.text().trim()]; + if (title && $title.css('display') !== 'none') + $title.after($title.clone().text(title)).css('display', 'none'); +} \ No newline at end of file diff --git a/src/func/translate/titleTransReact.ts b/src/func/translate/titleTransReact.ts new file mode 100644 index 0000000..b5c1583 --- /dev/null +++ b/src/func/translate/titleTransReact.ts @@ -0,0 +1,8 @@ +import {titleDict} from "../../dictionary/translation"; + +export default function titleTransReact(dom = document.querySelectorAll('h4[class^="title___"]')) { + dom.forEach(e => { + const title_trans = titleDict[e.innerText.trim()]; + if (title_trans) e.innerText = title_trans; + }); +} \ No newline at end of file diff --git a/src/func/translate/translateMain.ts b/src/func/translate/translateMain.ts new file mode 100644 index 0000000..d7e5dd1 --- /dev/null +++ b/src/func/translate/translateMain.ts @@ -0,0 +1,2096 @@ +import { + attackDict, + awDict, + calDict, + CC_set, + chatDict, + cityDict, + eduDict, + eventsDict, + gymDict, + gymList, + headerDict, + homeDict, + hosDict, + itemNameDict, + itemPageDict, + newspaperDict, + npcShopDict, + pcDict, + profileDict, + propertyDict, + sendCashDict, + sidebarDict, + stockDict, + tipsDict, + titleDict, + tornSettingsDict, + travelingDict +} from "../../dictionary/translation"; +import sendCashTrans from "./sendCashTrans"; +import eventsTrans from "./eventsTrans"; +import playerStatusTrans from "./playerStatusTrans"; +import initOB from "./initOB"; +import titleTrans from "./titleTrans"; +import contentTitleLinksTrans from "./contentTitleLinksTrans"; +import showItemInfoTrans from "./showItemInfoTrans"; +import log from "../utils/log"; +import contentTitleLinksTransReact from "./contentTitleLinksTransReact"; +import titleTransReact from "./titleTransReact"; + +export default function translateMain(href: string): void { + // 时分秒转换 + String.prototype.replaceHMS = function replaceHMS() { + return this.replace('and', '') + .replace('days', '天') + .replace('days', '天') + .replace('hours', '小时') + .replace('hour', '小时') + .replace('minutes', '分钟') + .replace('minute', '分钟') + .replace('seconds', '秒钟') + .replace('second', '秒钟'); + }; + + // 数词转换 a an some + String.prototype.numWordTrans = function numWordTrans() { + return this.replace(/\ban\b/, '1 个') + .replace(/\ba\b/, '1 个') + .replace(/\bsome\b/, '1 个') + .replace(/([0-9])x\b/, '$1 个'); + }; + + // 边栏 + let sidebarTimeOut = 60; + const sidebarInterval = setInterval(() => { + // 60秒后取消定时 + if ($('div[class^="sidebar"]').length === 0) { + sidebarTimeOut--; + if (sidebarTimeOut < 0) { + clearInterval(sidebarInterval); + } + return; + } + // 边栏块标题 + $('h2[class^="header"]').each((i, e) => { + if (!sidebarDict[e.firstChild.nodeValue]) return; + e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue]; + }); + // 边栏人物名字 + $('span[class^="menu-name"]').each((i, e) => { + e.firstChild.nodeValue = '名字:'; + }); + // 钱 等级 pt 天赋点 + $('p[class^="point-block"]').each((i, e) => { + if (sidebarDict[e.firstChild.firstChild.nodeValue]) + e.firstChild.firstChild.nodeValue = sidebarDict[e.firstChild.firstChild.nodeValue]; + }); + // 4条 状态条 + $('p[class^="bar-name"]').each((i, e) => { + if (sidebarDict[e.firstChild.nodeValue]) + e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue]; + }); + // 边栏菜单 + $('span[class^="linkName"]').each((i, e) => { + if (sidebarDict[e.firstChild.nodeValue]) + e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue]; + }); + // [use]按钮 + if (document.querySelector('#pointsMerits')) + $('#pointsMerits')[0].firstChild.nodeValue = '[使用]'; + if (document.querySelector('#pointsPoints')) + $('#pointsPoints')[0].firstChild.nodeValue = '[使用]'; + if (document.querySelector('#pointsLevel')) + $('#pointsLevel')[0].firstChild.nodeValue = '[升级]'; + + // 手机 区域菜单 + $('div[class*="areas-mobile"] span:nth-child(2)').contents().each((i, e) => { + //log(e); + if (sidebarDict[e.nodeValue]) + e.nodeValue = sidebarDict[e.nodeValue]; + }); + + clearInterval(sidebarInterval); + }, 1000); + + // header + if (document.querySelector('div#header-root')) { + const headerOB = new MutationObserver(_ => { + headerOB.disconnect(); + headerTrans(); + headerOB.observe($('div#header-root')[0], {childList: true, subtree: true, attributes: true}); + }); + + const headerTrans = function headerTrans() { + // 搜索内容下拉框中的文字 已选中 + if (headerDict[$('div.find button.toggler.down').text()]) + $('div.find button.toggler.down').text(headerDict[$('div.find button.toggler.down').text()]); + // pc端 搜索下拉框点击后的搜索类型文字 + $('div.find li.item').each((i, e) => { + if (headerDict[$(e).text()]) + $(e).text(headerDict[$(e).text()]); + }); + // 手机端 搜索下拉框点击后的搜索类型文字 + $('li[class^="search-type-"] label').each((i, e) => { + if (headerDict[$(e).text()]) + $(e).text(headerDict[$(e).text()]); + }); + // 搜索框placeholder + if (headerDict[$('input[class^="searchInput"]').attr('placeholder')]) + $('input[class^="searchInput"]').attr('placeholder', + headerDict[$('input[class^="searchInput"]').attr('placeholder')]); + // 高级搜索框 search by + if (headerDict[document.querySelector('div#header-root legend.title').innerText]) + $('div#header-root legend.title').text(headerDict[$('div#header-root legend.title').text()]); + // 高级搜索框的条件 左 键 + $('ul.advancedSearchFormBody label.label').each((i, e) => { + if (headerDict[$(e).text()]) + $(e).text(headerDict[$(e).text()]); + }); + // 高级搜索框的已选中 + $('ul.advancedSearchFormBody div.select-wrapper button.toggler.down').each((i, e) => { + // log($(e).text()) + if (headerDict[$(e).text().trim()]) + $(e).text(headerDict[$(e).text().trim()]); + else if (propertyDict[$(e).text().trim()]) + $(e).text(propertyDict[$(e).text().trim()]); + }); + // 高级搜索的下拉选项 + $('ul.advancedSearchFormBody li.item').each((i, e) => { + if (headerDict[$(e).text()]) + $(e).text(headerDict[$(e).text()]); + else if (propertyDict[$(e).text()]) + $(e).text(propertyDict[$(e).text()]); + }); + // 高级搜索的"Not" + $('ul.advancedSearchFormBody label.search-condition-not').each((i, e) => { + if (headerDict[$(e).text()]) + $(e).text(headerDict[$(e).text()]); + }); + // 高级搜索的"to" + $('ul.advancedSearchFormBody label[for*="To"]').each((i, e) => { + if (headerDict[$(e).text()]) + $(e).text(headerDict[$(e).text()]); + }); + // 高级搜索的reset search按钮 + $('form.form-search-extend div.bottom button').each((i, e) => { + if (headerDict[$(e).text()]) + $(e).text(headerDict[$(e).text()]); + }); + // log按钮“view log” + const $view_log = $('div.recentHistory a[class^="link"] span[class^="text"]') + if (headerDict[$view_log.text().trim()]) + $view_log + .text(headerDict[$view_log.text().trim()]); + // 点击头像打开的菜单 + $('ul.settings-menu span').each((i, e) => { + if (headerDict[$(e).text()] && e.childNodes.length === 1) + $(e).text(headerDict[$(e).text()]); + else if (e.childNodes.length === 3) + if (headerDict[e.firstChild.nodeValue]) + e.firstChild.nodeValue = headerDict[e.firstChild.nodeValue]; + }); + }; + headerTrans(); + headerOB.observe($('div#header-root')[0], {childList: true, subtree: true, attributes: true}); + } + + // chatbox + if (document.querySelector('div#chatRoot')) { + const chatOB = new MutationObserver(_ => { + chatOB.disconnect(); + chatTrans(); + chatOB.observe($('div#chatRoot').get(0), {childList: true, subtree: true, attributes: true}); + }); + const chatTrans = function chatTrans() { + // 聊天框的标题 + $('div#chatRoot div[class^="chat-box-title"] span[class^="name"]').each((i, e) => { + if (chatDict[$(e).text().trim()]) + $(e).text(chatDict[$(e).text().trim()]); + }); + // 聊天设置的左边label + $('div[class^="chat-settings-opts"] div[class*="label"]').each((i, e) => { + if ($(e).next().children('div.rc-slider').length > 0) { + // 高度和宽度有响应式的% + if (chatDict[$(e).text().split(' ')[0]]) { + $(e).text($(e).text().replace($(e).text().split(' ')[0], chatDict[$(e).text().split(' ')[0]])); + } + return; + } + if (chatDict[$(e).text().trim()]) + $(e).text(chatDict[$(e).text().trim()]); + }); + // 选项下拉栏 + $('div[class^="dropdown-root"]').find('*').contents().each((i, e) => { + if (e.nodeType !== 3) return; + if (chatDict[e.nodeValue]) + e.nodeValue = chatDict[e.nodeValue]; + }); + // 设置的两个选项 + $('label[class^="privacy-label"]').each((i, e) => { + if (chatDict[$(e).text().trim()]) + $(e).text(chatDict[$(e).text().trim()]); + }); + // people中的5个分类 faction friend... + $('ul[class^="type-list"] li a').each((i, e) => { + if (chatDict[$(e).text().trim()]) + $(e).text(chatDict[$(e).text().trim()]); + }); + // people中的列表添加框placeholder + $('div.ac-wrapper input.ac-search').each((i, e) => { + if (chatDict[$(e).attr('placeholder')]) + $(e).attr('placeholder', chatDict[$(e).attr('placeholder')]); + }); + // + if (eventsDict[$('div#chatRoot div[class^="overview"] > div > div:nth-child(2)').text().trim()]) { + $('div#chatRoot div[class^="overview"] > div > div:nth-child(2)') + .text( + eventsDict[document.querySelector('div#chatRoot div[class^="overview"] > div > div:nth-child(2)').innerText.trim()] + ); + } + }; + chatTrans(); + chatOB.observe($('div#chatRoot').get(0), {childList: true, subtree: true, attributes: true}); + } + + // 搜索玩家的4个分类按钮 + const playerSearchBoxTrans = function playerSearchBoxTrans() { + const opt = { + childList: true, + subtree: true, + }; + const psbtOB = new MutationObserver(mutation => { + const $people_cat = $('ul.ac-options li a'); + psbtOB.disconnect(); + mutation.forEach((e) => { + if ((e.target).className === 'ac-wrapper') { + $people_cat.each((i, e) => { + if (chatDict[$(e).text().trim()]) + $(e).text(chatDict[$(e).text().trim()]); + }); + } + }) + psbtOB.observe(document.body, opt); + }); + psbtOB.observe(document.body, opt); + } + playerSearchBoxTrans(); + + // 飞行页面 + if (href.includes('index.php') && + !!document.querySelector('div.travelling h4')) { + const travelOB = new MutationObserver(travelOBInit); + + function travelOBInit() { + travelOB.disconnect(); + travelTrans(); + travelOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); + } + + function travelTrans() { + titleTrans(); + contentTitleLinksTrans(); + + // 气泡 + if (tipsDict[document.querySelector('div.inner-popup').innerText.trim()]) + $('div.inner-popup').text(tipsDict[$('div.inner-popup').text().trim()]); + // Remaining Flight Time - + $('div.destination-title span').contents().each((i, e) => { + if (e.childNodes.length !== 0) return; + if (!e.nodeValue) return; + if (travelingDict[e.nodeValue.trim()]) + e.nodeValue = travelingDict[e.nodeValue.trim()]; + }); + // torntools扩展插件落地时间 + if (document.querySelector('div.tt-landing-time span.description').innerText.split(' ')[0] === 'Landing') { + let node = $('div.tt-landing-time span.description'); + const landingTime = node.text().slice(11, 19); + node.text('于 ' + landingTime + ' 降落'); + } + } + + travelTrans(); + travelOB.observe(document.querySelector('div.content-wrapper'), {childList: true, subtree: true}); + } + + // 主页 + if (href.contains(/index\.php/) && document.querySelector('h4#skip-to-content').innerText.contains(/Home/)) { + titleTrans(); + contentTitleLinksTrans(); + // 主页黑框标题文字翻译 + $('h5.box-title').each((i, e) => { + if (!homeDict[e.firstChild.nodeValue]) return; + // 翻译最近5条通知 + if (e.firstChild.nodeValue === 'Latest Events') { + //homeEvents = $(e).parent().next().find('span'); + eventsTrans($(e).parent().next().find('span')); + } + // 翻译最近5个攻击 + else if (e.firstChild.nodeValue === 'Latest Attacks') { + $(e).parent().next().find('span').each(function () { + let nodes = $(this)[0].childNodes; + nodes.forEach((v, i) => { + if (v.nodeValue !== null) { + let waitToTsf = v.nodeValue.toString().indexOf(" "); + let words = v.nodeValue.replace("\n", "").toString().split(" "); + words.forEach((word, j) => { + if (attackDict.hasOwnProperty(word)) { + if (word === "Someone") { + $(this)[0].childNodes[i].nodeValue = $(this)[0].childNodes[i].nodeValue.replace(" ", ""); + } + let change = $(this)[0].childNodes[i].nodeValue.replace(word, attackDict[word]); + $(this)[0].childNodes[i].nodeValue = change; + + } + }) + } + }, this); + }); + } + //e.firstChild.nodeValue = homeDict[e.firstChild.nodeValue]; + // 隐藏原dom元素避免与torntools发生冲突 + if ($(e).css('display') !== 'none') + $(e).css('display', 'none').after(`
` + homeDict[e.firstChild.nodeValue] + `
`); + }); + // 各表格左边的键 + $('span.divider span').each((i, e) => { + if (homeDict[$(e).text()]) + $(e).text(homeDict[$(e).text()]); + }); + return; + } + + // city + if (href.includes('city.php')) { + const cityOB = new MutationObserver(cityOBInit); + + function cityOBInit() { + cityOB.disconnect(); + cityTrans(); + cityOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); + } + + function cityTrans() { + titleTrans(); + contentTitleLinksTrans(); + + // Map or Quick Links + $('a.ui-tabs-anchor span').each((i, e) => { + if (cityDict[$(e).text()]) + $(e).text(cityDict[$(e).text()]); + }); + + // 标志建筑 标题 + if (cityDict[$('div.title-black').text()]) + $('div.title-black').text(cityDict[$('div.title-black').text()]); + + // 标志建筑 6个分类 + $('ul.map-symbols span').each((i, e) => { + if (cityDict[$(e).text()]) + $(e).text(cityDict[$(e).text()]); + }); + + // 地图显示模式 + // 不完全显示 文字 + $('span.inactive-mode').html(cityDict['inactive-mode1'] + `
` + cityDict['inactive-mode2']); + // 完全显示 文字 + $('span.active-mode').text(cityDict['active-mode']); + // 开关 + $('div.on-label').text('已开启'); + $('div.off-label').text('已关闭'); + + // 快速链接中的分类标题 + $('li.title').each((i, e) => { + if (cityDict[$(e).text()]) + $(e).text(cityDict[$(e).text()]); + }); + + // 快速链接中的区域 + $('li a[class^="font-num-"] span').each((i, e) => { + // log($(e).prev().attr('class')==='cql-gym') + if (cityDict[$(e).text()]) { + $(e).text(cityDict[$(e).text()]); + } else if ($(e).prev().attr('class') === 'cql-your-property') { + if (propertyDict[$(e).text().trim().slice(5)]) { + $(e).text('你的' + propertyDict[$(e).text().trim().slice(5)]); + } + } else if ($(e).prev().attr('class') === 'cql-gym') { + if (gymList[$(e).text().trim()]) { + $(e).text(gymList[$(e).text()]); + } else if (gymList[$(e).text().trim().split(' ').slice(0, 2).join(' ')]) { + $(e).text(gymList[$(e).text().trim().split(' ').slice(0, 2).join(' ')]); + } + } + }); + + // 快速链接中的分类选择 + $('div.sort-by label.marker-css').each((i, e) => { + if (cityDict[$(e).text()]) + $(e).text(cityDict[$(e).text()]); + }); + + // 快速链接中的sort by + $('span#wai-sort-by').each((i, e) => { + if (cityDict[$(e).text()]) + $(e).text(cityDict[$(e).text()]); + }); + } + + cityTrans(); + cityOB.observe(document.querySelector('div.content-wrapper'), {childList: true, subtree: true}); + return; + } + + // gym健身房页面 + if (href.includes('gym.php')) { + const gymOB = new MutationObserver(gymOBInit); + + function gymOBInit() { + gymOB.disconnect(); + gymTrans(); + gymOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); + } + + function gymTrans() { + titleTrans(); + contentTitleLinksTrans(); + const gymName = $('div[class^="notificationText"] b').text(); + + // 顶部提示信息 + $('div[class^="notificationText"] p').contents().each((i, e) => { + if (e.nodeName === 'B' && gymList[$(e).text().trim()]) { + $(e).text(gymList[$(e).text().trim()]); + return; + } + if (e.childNodes.length === 0 && gymDict[e.nodeValue.trim()]) + e.nodeValue = gymDict[e.nodeValue.trim()]; + }); + // 4属性标题 + $('h3[class^="title"]').each((i, e) => { + if (gymDict[$(e).text().trim()]) + $(e).text(gymDict[$(e).text().trim()]); + }); + // 4属性的介绍 与冰蛙冲突 + $('div[class^="description"] p:nth-child(1)').each((i, e) => { + if (gymDict[$(e).text().trim()]) + $(e).text(gymDict[$(e).text().trim()]); + }); + // 每次锻炼的花销 + $('div[class^="description"] p:nth-child(2)').each((i, e) => { + if (e.childNodes.length === 1) { + if (gymDict[$(e).text().trim()]) + $(e).text(gymDict[$(e).text().trim()]); + } else if (e.childNodes.length === 2) { + if (gymDict[e.lastChild.nodeValue.trim()]) { + e.lastChild.nodeValue = gymDict[e.lastChild.nodeValue.trim()]; + } + } + }); + // 锻炼页面所有按钮 + $('button[class^="button"]').each((i, e) => { + if (gymDict[$(e).text().trim()]) + $(e).text(gymDict[$(e).text().trim()]); + }); + // cancel按钮 + $('button[class^="cancel"]').each((i, e) => { + if (gymDict[$(e).text().trim()]) + $(e).text(gymDict[$(e).text().trim()]); + }); + // 锻炼的提示信息 + $('div[class^="messageWrapper"] p').each((i, e) => { + /** + * todo + *

You dug deep and completed 15 minutes of incline sprints

+ * + */ + if (gymDict[$(e).text()]) + $(e).text(gymDict[$(e).text()]); + }); + // 健身房信息 标题 + $('div[class^="gymTitle"] h3').each((i, e) => { + if (gymDict[$(e).text()]) + $(e).text(gymDict[$(e).text()]); + else if (gymList[$(e).text().trim()]) + $(e).text(gymList[$(e).text().trim()]); + }); + // 健身房信息 属性名 + $('ul[class^="gymInfo"] b').each((i, e) => { + if (gymDict[$(e).text().trim()]) + $(e).text(gymDict[$(e).text().trim()]); + }); + + // 健身房状态信息 + // $('div[class^="gymStats"] b').each((i, e) => { + // log(e) + // if (gymDict[$(e).text().trim()]) + // $(e).text(gymDict[$(e).text().trim()]); + // }); + // + // // 健身房状态值 + // $('div[class^="gymStats"] span[class^=value]').each((i, e) => { + // if ($(e).text().indexOf("per train") > 0) + // $(e).text($(e).text().split(" ")[0] + gymDict["per train"]); + // else if (gymDict[$(e).text().trim()]) + // $(e).text(gymDict[$(e).text().trim()]); + // }); + + // 健身房信息 属性值 + $('ul[class^="gymInfo"] span[class^="value"]').each((i, e) => { + if (gymDict[$(e).text().trim()]) + $(e).text(gymDict[$(e).text().trim()]); + }); + // 健身房信息 具体锻炼项目 + $('span[class^="exerciseName"]').each((i, e) => { + if (gymDict[$(e).text().trim()]) + $(e).text(gymDict[$(e).text().trim()]); + }); + // 购买提示信息 + $('div[class^="confirmMessage"] p[role="alert"]').each((i, e) => { + if (gymDict[$(e).text().trim()]) + $(e).text(gymDict[$(e).text().trim()]); + }); + } + + gymTrans(); + gymOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); + return; + } + + // 物品页面 + if (href.contains(/item\.php/)) { + if (href.includes('item.php?temp=')) return; + // 标题和右边的链接 + initOB(document.querySelector('.content-title'), {childList: true}, + () => { + titleTrans(); + contentTitleLinksTrans(); + }); + // 套装预览中间的文字 + const $loadouts_root = document.getElementById('loadoutsRoot'); + if ($loadouts_root) { + initOB($loadouts_root, {subtree: true, attributes: true}, () => { + const el = $loadouts_root.querySelector('div[class^="type___"]'); + if (el && itemPageDict[el.innerText.trim()]) { + el.innerText = itemPageDict[el.innerText.trim()]; + } + }); + } + // 手机选项按钮 物品名 物品详情 + const options = { + attributes: true, + subtree: true, + attributeFilter: ["aria-hidden",] + }; + const translated = {cat: '', count: -1}; + const translatedOnce = {item_opt: -1, opt_icon_count: -1}; + initOB(document.getElementById('category-wrap'), options, () => { + // 手机操作选项 + const $item_opt = document.querySelectorAll(`ul.itemsList span.opt-name`); + if (translatedOnce.item_opt !== $item_opt.length - 1) { + let count = -1; + $item_opt.forEach((e, i) => { + if (itemPageDict[e.firstChild.nodeValue.trim()]) { + e.firstChild.nodeValue = itemPageDict[e.firstChild.nodeValue.trim()]; + } + count = i; + }); + translatedOnce.item_opt = count !== -1 ? count : -1; + } + // 物品名 + const $active_tab = document.querySelector('ul.itemsList[aria-expanded="true"]'); + if (!$active_tab) return; + const $active_item_list = $active_tab.querySelectorAll('span.name'); + const itemCat = $active_tab.id; + if ($active_item_list.length - 1 !== translated.count || itemCat !== translated.cat) { + let count = -1; + // 物品名 + $active_item_list.forEach((e, i) => { + if (!e.classList.contains('wh-translated')) { + if (itemNameDict[e.innerText.trim()]) { + e.classList.add('wh-translated'); + const trans_dom = document.createElement('span'); + trans_dom.classList.add('wh-translate'); + trans_dom.setAttribute('style', 'margin: 0 0 0 1em'); + trans_dom.append(itemNameDict[e.innerText.trim()]); + e.after(trans_dom); + // .after(`${itemNameDict[$(e).text().trim()]}`); + } + } + count = i; + }); + + if (count !== -1) { + translated.cat = itemCat; + translated.count = count; + } + } + // 物品详情 + const $show_item_info: HTMLElement = $active_tab.querySelector('li.show-item-info'); + showItemInfoTrans($show_item_info); + // 物品右操作按钮 + const $opt_icon_tooltip = $('ul.actions-wrap span.icon-h'); + if (translatedOnce.opt_icon_count !== $opt_icon_tooltip.length - 1) { + let count = -1 + $opt_icon_tooltip.each((i, e) => { + if (itemPageDict[e.getAttribute('title')]) { + e.setAttribute('title', itemPageDict[e.getAttribute('title')]); + } + count = i; + }); + if (count !== -1) { + translatedOnce.opt_icon_count = count; + } + } + }); + // 黑框 + const $title_black = document.querySelector('div.title-black'); + if ($title_black) { + const $your_items = $title_black.querySelector('span.m-hide'); + if (itemPageDict[$your_items.innerText.trim()]) { + $your_items.innerText = itemPageDict[$your_items.innerText.trim()]; + } + // 黑框分类标题 + const $items_type_name = $title_black.querySelector('span.items-name'); + initOB($items_type_name, {childList: true}, () => { + if (itemPageDict[$items_type_name.innerText.trim()]) { + $items_type_name.innerText = itemPageDict[$items_type_name.innerText.trim()]; + } + }); + } + // 分类浮动文字 + const $data_type = document.querySelectorAll('li#categoriesItem a'); + $data_type.forEach((e) => { + if (itemPageDict[e.getAttribute('title')]) { + e.setAttribute('title', itemPageDict[e.getAttribute('title')]); + } + }); + return; + } + + // npc商店 + if (href.contains(/(shops|bigalgunshop)\.php/)) { + // 标题和右边的链接 + const $cont_title = document.querySelector('.content-title'); + initOB($cont_title, {childList: true, subtree: true}, () => { + titleTrans(); + contentTitleLinksTrans(); + }); + const $wrapper = document.querySelector('.content-wrapper'); + // [购买部分] + const $buy_items_wrapper = $wrapper.querySelector('.buy-items-wrap'); + if ($buy_items_wrapper) { + // 黑框标题 + const $buy_black_title = $buy_items_wrapper.querySelector('.title-black'); + if ($buy_black_title && npcShopDict[$buy_black_title.firstChild.nodeValue.trim()]) { + $buy_black_title.firstChild.nodeValue = npcShopDict[$buy_black_title.firstChild.nodeValue.trim()]; + } + // 各个物品 + const $items = $buy_items_wrapper.querySelectorAll('ul.items-list > li.torn-divider'); + $items.forEach(e => { + // 物品名 + const $item_name = e.querySelector('span.desc span.name.bold'); + if ($item_name && itemNameDict[$item_name.innerText.trim()]) { + $item_name.innerText = `${itemNameDict[$item_name.innerText.trim()]}(${$item_name.innerText.trim()})`; + } + // 类型和存货 + const $item_stock = e.querySelector('span.desc span.stock'); + if ($item_stock) $item_stock.childNodes.forEach(e => { + if (e.nodeType === 1) { + if (npcShopDict[(e).innerText.trim()]) (e).innerText = npcShopDict[(e).innerText.trim()]; + } else { + if (npcShopDict[e.nodeValue.trim()]) e.nodeValue = npcShopDict[e.nodeValue.trim()]; + } + }); + // buy按钮 + const $buy_btn = e.querySelector('button.wai-support'); + if ($buy_btn && npcShopDict[$buy_btn.childNodes[0].nodeValue.trim()]) { + $buy_btn.childNodes[0].nodeValue = npcShopDict[$buy_btn.childNodes[0].nodeValue.trim()]; + } + // 买前确认 + const $confirm = e.querySelector('span.confirm'); + const $confirm_msg = $confirm.querySelector('span'); + if ($confirm_msg && npcShopDict[$confirm_msg.innerText.trim()]) { + $confirm_msg.innerText = npcShopDict[$confirm_msg.innerText.trim()]; + } + const $amount_item_name = $confirm.querySelector('span.count').nextSibling; + if ($amount_item_name && !$amount_item_name.nodeValue.contains(CC_set)) { + const item_name = $amount_item_name.nodeValue.trim().split(' ').slice(1, -1).join(' '); + const item_name_trans = itemNameDict[item_name] || item_name; + $amount_item_name.nodeValue = `个[${item_name_trans}],总计$`; + } + const $confirm_a = $confirm.querySelectorAll('span.confirm-act a'); + $confirm_a.forEach(e => { + if (npcShopDict[e.innerText.trim()]) e.innerText = npcShopDict[e.innerText.trim()]; + }); + }); + // 展开的物品详情 + initOB($wrapper, {childList: true, subtree: true}, () => { + const $item_desc: HTMLElement = $wrapper.querySelector('.show-item-info') || $wrapper.querySelector('.view-item-info'); + showItemInfoTrans($item_desc); + }); + } + // [卖出部分] + const $sell_items_wrapper = $wrapper.querySelector('.sell-items-wrap'); + if ($sell_items_wrapper) { + // 黑框标题 + const $title = $sell_items_wrapper.querySelectorAll('ul.title li'); + $title.forEach(el => { + el.childNodes.forEach(e => { + if (e.nodeType === 1) { + if (npcShopDict[e.innerText.trim()]) { + e.innerText = npcShopDict[e.innerText.trim()]; + return; + } + const spl = e.innerText.trim().split(' '); + if (spl.length > 3) { + const shop_name = spl[2] === 'the' ? spl.slice(3).join(' ') : spl.slice(2).join(' '); + const shop_name_trans = npcShopDict[shop_name] || titleDict[shop_name] || cityDict[shop_name] || null; + e.innerText = `物品给${shop_name_trans || shop_name}`; + } + } else { + if (npcShopDict[e.nodeValue.trim()]) e.nodeValue = npcShopDict[e.nodeValue.trim()]; + } + }); + }); + // 物品名 + const $items_name = $sell_items_wrapper.querySelectorAll('span.name'); + $items_name.forEach(el => { + if (itemNameDict[el.innerText.trim()]) el.innerText += + ` ${itemNameDict[el.innerText.trim()]}`; + }); + // 按钮 + const $btn = $sell_items_wrapper.querySelectorAll('button'); + $btn.forEach(e => { + if (npcShopDict[e.innerText.trim()]) e.innerText = npcShopDict[e.innerText.trim()]; + }); + // select btn + const $select_btn = $sell_items_wrapper.querySelector('li.select button.wai-btn'); + if ($select_btn) { + initOB($select_btn, {childList: true}, () => { + if ($select_btn && npcShopDict[$select_btn.innerText.trim()]) { + $select_btn.innerText = npcShopDict[$select_btn.innerText.trim()]; + } + }); + } + // 取消按钮 + const $cancel = $sell_items_wrapper.querySelector('span.cancel a'); + if ($cancel && npcShopDict[$cancel.innerText.trim()]) { + $cancel.innerText = npcShopDict[$cancel.innerText.trim()]; + } + // 卖出确认文字 + const $sell_confirm = $sell_items_wrapper.querySelector('div.sell-confirm'); + if ($sell_confirm) { + const $msg = $sell_confirm.childNodes[0]; + if (npcShopDict[$msg.nodeValue.trim()]) $msg.nodeValue = npcShopDict[$msg.nodeValue.trim()]; + const $total_value = $sell_confirm.querySelector('span.profit').childNodes[0]; + if (npcShopDict[$total_value.nodeValue.trim()]) $total_value.nodeValue = npcShopDict[$total_value.nodeValue.trim()]; + } + } + // [出售PT部分] + const $sell_pt_wrapper = $wrapper.querySelector('.sell-points-wrap'); + if ($sell_pt_wrapper) { + // 黑框 + const $title_black = $sell_pt_wrapper.querySelector('.title-black'); + if (npcShopDict[$title_black.innerText.trim()]) { + $title_black.innerText = npcShopDict[$title_black.innerText.trim()]; + } + } + return; + } + + // 股票 + if (href.contains(/page\.php\?sid=stocks/)) { + const stockOB = new MutationObserver(() => { + stockOB.disconnect(); + titleTrans(); + contentTitleLinksTrans(); + stockTrans(); + stockOB.observe($('.content-wrapper').get(0), { + characterData: true, + attributes: true, + subtree: true, + childList: true + }); + }); + const stockTrans = function stockTrans() { + // 表头 + $('ul.title-black').find('*').contents().each((i, e) => { + if (e.nodeType === 3 && stockDict[e.nodeValue.trim()]) { + e.nodeValue = stockDict[e.nodeValue.trim()]; + } + }); + // 名称 + $('div[class^="nameContainer"]').each((i, e) => { + if (e.childNodes[0].nodeValue && stockDict[e.childNodes[0].nodeValue.trim()]) { + e.childNodes[0].nodeValue = stockDict[e.childNodes[0].nodeValue.trim()]; + } + }); + // 右侧bb名 + $('div[class^="dividendInfo"] p').each((i, e) => { + const spl = $(e).text().trim().split(' '); + if (stockDict[$(e).text().trim()]) { + $(e).text(stockDict[$(e).text().trim()]); + } else if (/[0-9]x$/.test(spl[0])) { + const itemName = spl.slice(1).join(' '); + const num = spl[0].slice(0, -1); + $(e).text(`${num}个${itemNameDict[itemName] ? itemNameDict[itemName] : itemName}`); + } + }); + // 股价详情 + $('#panel-priceTab ul[role="tablist"] label span:last-child').each((i, e) => { + if (stockDict[$(e).text()]) { + $(e).text(stockDict[$(e).text()]); + } + }); + $('ul[class^="priceInfoList___"] li').contents().each((i, e) => { + if (e.nodeType === 3) { + if (stockDict[e.nodeValue.trim()]) { + e.nodeValue = stockDict[e.nodeValue.trim()]; + } + } + }); + // 点开购买后 + $('div#panel-ownedTab div[class^="manageBlock"] *').contents().each((i, e) => { + if (e.nodeType === 1) { + if (stockDict[$(e).text().trim()]) { + $(e).text(stockDict[$(e).text().trim()]); + } + } else if (e.nodeType === 3) { + if (stockDict[e.nodeValue.trim()]) e.nodeValue = stockDict[e.nodeValue.trim()]; + else if (/\$[0-9]+ after the 0\.1% fee of \$[0-9]+$/.test(e.nodeValue.trim())) { + e.nodeValue = e.nodeValue.trim() + .replace('after the', stockDict['after the']) + .replace('fee of', stockDict['fee of']); + } + } + }); + // 点开购买后的历史栏 + $('div#panel-ownedTab div[class^="transactionsContainer"] li').each((i, e) => { + e = e.childElementCount === 0 ? e : e.children[0] as HTMLElement; + if (stockDict[$(e).text().trim()]) { + $(e).text(stockDict[$(e).text().trim()]); + } + }); + // 历史购买show more + const $show_more = document.querySelector('li[class^="showMore___"] button'); + if ($show_more && $show_more.innerText.trim().contains(/^Show [0-9]+ more$/)) { + const number = $show_more.innerText.trim().split(' ')[1]; + $show_more.innerText = `显示另外${number}条`; + } + // 点开bb后 + $('div#panel-dividendTab div[class^="message"] *').contents().each((i, e) => { + if (e.nodeType !== 3) return; + if (!e.nodeValue.trim()) return; + if (stockDict[e.nodeValue.trim()]) { + e.nodeValue = stockDict[e.nodeValue.trim()]; + } + // 第n个increment 1st 2nd 3rd 4th + else if (/[0-9][snrt][tdh]$/.test(e.nodeValue.trim())) { + e.nodeValue = `第${e.nodeValue.trim().slice(0, -2)}个`; + } + // 物品 + else if (/[0-9]x$/.test(e.nodeValue.trim().split(' ')[0])) { + const spl = e.nodeValue.trim().split(' '); + const itemName = spl.slice(1).join(' '); + e.nodeValue = + ` ${spl[0].replace('x', '个') + } ${itemNameDict[itemName] ? itemNameDict[itemName] : itemName + }`; + } else { + if (/[\u4e00-\u9fa5]/.test(e.nodeValue)) return; + if (/\b\$?[0-9,]+$/.test(e.nodeValue)) return; + log.info(`未找到翻译:[${e.nodeValue.trim()}]`); + } + }); + }; + stockTrans(); + stockOB.observe($('.content-wrapper').get(0), { + characterData: true, + attributes: true, + subtree: true, + childList: true + }); + return; + } + + // 教育页面 + if (href.indexOf('education.php') >= 0) { + const eduOB = new MutationObserver(eduOBInit); + + function eduOBInit() { + eduOB.disconnect(); + eduTrans(); + eduOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); + } + + function eduTrans() { + titleTrans(); + contentTitleLinksTrans(); + + // 大科目、学院标题 + $('div.content-wrapper div.title').each((i, e) => { + if (eduDict[$(e).text().trim()]) + e.firstChild.nodeValue = eduDict[$(e).text().trim()]; + }); + // 教育主页提示内容 和 学院详情 小课程提示信息 + $('div.content-wrapper div[class^="msg"]').find('*').contents().each((i, e) => { + if (e.nodeValue === null) return; + if (eduDict[e.nodeValue.trim()]) { + e.nodeValue = eduDict[e.nodeValue.trim()]; + } else if (e.nodeValue.indexOf('second') >= 0 || + e.nodeValue.indexOf('minute') >= 0 || + e.nodeValue.indexOf('hour') >= 0 || + e.nodeValue.indexOf('day') >= 0) { + e.nodeValue = e.nodeValue + .replace('days', '天') + .replace('day', '天') + .replace('hours', '时') + .replace('hour', '时') + .replace('minutes', '分') + .replace('minute', '分') + .replace('and', '和') + .replace('seconds', '秒') + .replace('second', '秒'); + } + }); + // 学院详情标题 + $('div.content-wrapper div.title-black').each((i, e) => { + if (e.childNodes.length === 3) + if (eduDict[e.lastChild.nodeValue.trim()]) + e.lastChild.nodeValue = ' ' + eduDict[e.lastChild.nodeValue.trim()]; + if (eduDict[$(e).text().trim()]) + $(e).text(eduDict[$(e).text().trim()]); + }); + // 学院详情 小课程标题 + $('div.content-wrapper span.module-name').each((i, e) => { + if (eduDict[$(e).text().trim()]) + $(e).text(eduDict[$(e).text().trim()]); + }); + // 学院详情 课程的描述 + $('div.content-wrapper p.desc').each((i, e) => { + if (eduDict[$(e).text().trim()]) + $(e).text(eduDict[$(e).text().trim()]); + }); + // 课程详情 7 标题 + $('div.module-desc p.title').each((i, e) => { + if (eduDict[$(e).text().trim()]) + $(e).text(eduDict[$(e).text().trim()]); + }); + // 课程介绍中的所有li元素 + $('div.module-desc ul.info').find('*').contents().each((i, e) => { + if (e.nodeValue === null) return; + if (eduDict[e.nodeValue.trim()]) + e.nodeValue = eduDict[e.nodeValue.trim()]; + else if (e.nodeValue.indexOf('Length') >= 0) { + e.nodeValue = e.nodeValue.replace('Length', eduDict['Length']) + .replace('d ', '日') + .replace('h ', '时') + .replace('m ', '分'); + } else if (e.nodeValue.indexOf('Cost') >= 0) { + e.nodeValue = e.nodeValue.replace('Cost', eduDict['Cost']); + } else if (e.nodeValue.indexOf('manual labor') >= 0) { + e.nodeValue = e.nodeValue.replace('manual labor', eduDict['manual labor']) + .replace('Gain', eduDict['Gain']) + .replace('upon completion', eduDict['upon completion']); + } else if (e.nodeValue.indexOf('endurance') >= 0) { + e.nodeValue = e.nodeValue.replace('endurance', eduDict['endurance']) + .replace('Gain', '获得') + .replace('upon completion', eduDict['upon completion']); + } else if (e.nodeValue.indexOf('intelligence') >= 0) { + e.nodeValue = e.nodeValue.replace('intelligence', eduDict['intelligence']) + .replace('Gain', '获得') + .replace('upon completion', eduDict['upon completion']); + } + }); + } + + eduTrans(); + eduOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); + return; + } + + // profile 玩家资料页面 + if (href.contains(/profiles\.php\?XID=\d+/)) { + const $wrapper = document.querySelector('.content-wrapper'); + const profileOB = new MutationObserver(() => { + profileOB.disconnect(); + titleTrans(); + contentTitleLinksTrans(); + profileTrans(); + profileOB.observe($wrapper, { + characterData: true, + attributes: true, + subtree: true, + childList: true + }); + }); + const profileTrans = function profileTrans() { + const playerName = document.title.trim().contains(/('s |s' )/) + ? document.title.trim().split(/('s |s' )/)[0] + : null; + if (!playerName) { + console.error('翻译助手错误:获取用户名失败。'); + try { + profileOB.disconnect() + } catch { + } + return; + } + + // 黑框标题 + $('.content-wrapper .title-black').each((i, e) => { + if (i === 1) { + if (profileDict[e.firstChild.nodeValue.trim().replace(playerName, '{$}')]) { + e.firstChild.nodeValue = ( + profileDict[$(e).text().trim().replace(playerName, '{$}')] + .replace('{$}', playerName) + ); + } + return; + } + if (profileDict[$(e).text().trim()]) { + $(e).text(profileDict[$(e).text().trim()]); + } + }); + // level rank age + $('.profile-information-wrapper .box-info .box-name').each((i, e) => { + if (profileDict[e.innerText.trim()]) e.innerText = profileDict[e.innerText.trim()]; + }); + // todo player title + // todo player rank title + // 行动框的描述 + const action_desc = $('#profile-container-description.profile-container-description'); + if (profileDict[action_desc.text().trim()]) { + action_desc.html(`${profileDict[action_desc.text().trim()]}`); + } else if (profileDict[action_desc.text().trim().replace(playerName, '{$}')]) { + action_desc.html( + `${profileDict[action_desc.text().trim().replace(playerName, '{$}')] + .replace('{$}', playerName)}` + ); + } else if (action_desc.text().contains(/is on your (friend|enemy) list/)) { + const spl = action_desc.text().trim().split(' '); + const mark = spl.length === 6 + ? null + : spl.slice(7).join(' '); + switch (spl[4]) { + case 'friend': + if (profileDict['{$} is on your friend list']) { + action_desc.html( + `${profileDict['{$} is on your friend list'] + .replace('{$}', playerName) + }${mark ? ' : ' + mark : '' + }` + ); + } + break; + case 'enemy': + if (profileDict['{$} is on your enemy list']) { + action_desc.html( + `${profileDict['{$} is on your enemy list'] + .replace('{$}', playerName) + }${mark ? ' : ' + mark : '' + }` + ); + } + break; + } + } else { + if ($('.wh-translated').length <= 0) { + log(`未找到翻译: “${action_desc.text().trim()}”`); + } + } + // 添加敌人或朋友的界面 + $('.add-user .reason-wrapper').find('*').contents().each((i, e) => { + if (e.nodeType === 3) { + if (profileDict[e.nodeValue.trim()]) { + e.nodeValue = profileDict[e.nodeValue.trim()]; + } else if (/\b[1-4]?[0-9]\b/.test(e.nodeValue.trim().slice(0, 2))) { + const left = e.nodeValue.trim().slice(0, 2); + if (profileDict['{$} characters left']) { + e.nodeValue = profileDict['{$} characters left'].replace('{$}', left); + } + } + } + }); + // 状态 + playerStatusTrans($('.profile-status .profile-container span')); + // 表格 + $('ul.info-table li div').each((i, e) => { + const $e = $(e); + // 左 + if ($e.attr('class').contains(/user-information-section/)) { + const elem = e.children[0]; + const $elem = $(elem); + if (profileDict[$elem.text().trim()]) $elem.text(profileDict[$elem.text().trim()]); + } + // 右 值 + else { + if (profileDict[$e.text().trim()]) { + $e.children().text(profileDict[$e.text().trim()]); + return; + } + switch (i) { + case 5: // 帮派 + case 7: { // 公司 + if ($e.text().contains(CC_set)) return; + const $span = e.children[0].children[0]; + const pos = $span.firstChild.nodeValue.trim().split(' ').slice(0, -1).join(' '); + $span.firstChild.nodeValue = ''; + $($span).append(` 的 ${pos}`); + return; + } + case 11: { + // 住宅 + $e.find('span *').contents().each((i, el) => { + if (el.nodeType === 3) { + if (profileDict[el.nodeValue.trim()]) { + el.nodeValue = profileDict[el.nodeValue.trim()] + } else if (propertyDict[el.nodeValue.trim()]) { + el.nodeValue = propertyDict[el.nodeValue.trim()] + } + } + }); + return; + } + case 13: { + // 结婚状态 + if ($e.text().contains(CC_set)) return; + const days = $e.text().contains(/ [0-9]+ /) + ? $e.text().trim().split(' ')[4] + : null; + if (days) { + e.children[0].children[0].childNodes[0].nodeValue = '与 '; + e.children[0].children[0].childNodes[2].nodeValue = ` 结婚${days}天`; + } else { + $e.find('span *').contents().each((i, el) => { + if (el.nodeType === 3) { + if (profileDict[el.nodeValue.trim()]) { + el.nodeValue = profileDict[el.nodeValue.trim()] + } + } + }); + } + return; + } + case 23: { + // 39 minutes ago + if ($e.text().contains(/ago/)) { + $e.children().text($e.text() + .replace('ago', '前') + .replace('and', '') + .replace('seconds', '秒') + .replace('second', '秒') + .replace('minutes', '分') + .replace('minute', '分') + .replace('hours', '时') + .replace('hour', '时') + .replace('days', '日') + .replace('day', '日') + .replaceAll(' ', '') + ); + } + return; + } + } + /** + 1 'Woohoo [2687093]' + 3 'Civilian' + 5 'Knight of Silver Hand' + 7 'Director of -- FaFaFa --' + 9 '1567 / 1567' + 11 'Private Island (With Spouse)' + 13 'Married to Sabrina_Devil for 42 days' + 15 '153' + 17 '4' + 19 '4\n  好人\n  坏比指数: 1\n ' + 21 '2 (0 karma)' + 23 '52 minutes ago' + */ + } + }); + // doesnt wish to share + const $nShare = $('.personal-info p'); + $nShare.contents().each((i, e) => { + if (e.nodeType === 3) { + if (profileDict[e.nodeValue.trim()]) e.nodeValue = profileDict[e.nodeValue.trim()]; + } + }); + // 活动状态 + const $cmpSt = $('.profile-container.competition-wrap span') + $cmpSt.text(profileDict[$cmpSt.text().trim()] || $cmpSt.text()); + + sendCashTrans('.content-wrapper'); + }; + profileTrans(); + profileOB.observe($wrapper, { + characterData: true, + attributes: true, + subtree: true, + childList: true + }); + return; + } + + // 报纸 + if (href.contains(/(newspaper|joblist|freebies|newspaper_class|personals|bounties|comics)\.php/)) { + const newspaperOB = new MutationObserver(() => { + newspaperOB.disconnect(); + newspaperTrans(); + newspaperOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); + }); + + function newspaperTrans() { + titleTrans(); + contentTitleLinksTrans(); + if ($('a.newspaper-link').length === 0) return; + // 导航菜单 + $('a.newspaper-link').contents().each((i, e) => { + if (newspaperDict[e.nodeValue]) + e.nodeValue = newspaperDict[e.nodeValue]; + }); + // 公众号广告 + $('div.price.left').contents()[2].nodeValue = '文章翻译请关注中文公众号Torncity'; + // 日期翻译 + const $date_label = document.querySelector('span.date-label'); + const date_reg = /^[FMSTW][adehinorstuy]+, [ADFJMNOS][abceglnoprtuvy]+ [1-3]?[0-9], 20[0-9][0-9]$/; + if ($date_label && $date_label.innerText.trim().contains(date_reg)) { + const date_format = $date_label.innerText.trim().replaceAll(',', ''); + const date_spl = date_format.split(' '); + const date = {w: date_spl[0], m: date_spl[1], d: date_spl[2], y: date_spl[3]}; + const month_trans = { + 'Jan': 1, + 'Feb': 2, + 'Mar': 3, + 'Apr': 4, + 'May': 5, + 'Jun': 6, + 'Jul': 7, + 'Aug': 8, + 'Sep': 9, + 'Oct': 10, + 'Nov': 11, + 'Dec': 12 + }; + $date_label.innerText = `${date.y}年${month_trans[date.m] || date.m}月${date.d}日`; + } + // 菜单下的信息 工作 壁纸 广告 悬赏 + $('div.help-message').find('*').contents().each((i, e) => { + if (!e.nodeValue || e.nodeValue.trim() === '') return; + if (newspaperDict[e.nodeValue.trim()]) + e.nodeValue = newspaperDict[e.nodeValue.trim()]; + else if (newspaperDict[e.nodeValue.trim().slice(0, 50)]) + e.nodeValue = newspaperDict[e.nodeValue.trim().slice(0, 50)]; + }); + // 右边栏 + $('div[class^="sideCont"] [class^="title"]').contents().each((i, e) => { + if (newspaperDict[e.nodeValue]) + e.nodeValue = newspaperDict[e.nodeValue]; + }); + // 彩票信息 + $('span[class^="winner"]').each((i, e) => { + }); + // 底部链接 + // Why not visit our sponsor? + if (newspaperDict[$('div.link-left').text().trim()]) + $('div.link-left').text(newspaperDict[$('div.link-left').text().trim()]); + // View all | Advertise here + $('div.link-right a').contents().each((i, e) => { + if (newspaperDict[e.nodeValue.trim()]) + e.nodeValue = newspaperDict[e.nodeValue.trim()]; + }) + $('.bounties-list-title li').each((i, e) => { + if (newspaperDict[$(e).text().trim()]) { + $(e).text(newspaperDict[$(e).text().trim()]); + } + }); + // 交友 + if (window.location.href.contains(/personals/)) { + $('div.personals-wrap span.msg').find('*').contents().each((i, e) => { + if (!e.nodeValue || e.nodeValue.trim() === '') return; + if (newspaperDict[e.nodeValue.trim()]) + e.nodeValue = newspaperDict[e.nodeValue.trim()]; + }); + } + // 漫画 + if (window.location.href.contains(/freebies/)) { + if (newspaperDict[$('div.bonus-wrap a').text().trim()]) + $('div.bonus-wrap a').text(newspaperDict[$('div.bonus-wrap a').text().trim()]); + } + // 悬赏 + if (window.location.href.contains(/bounties/)) { + // 列表前的总数 + const $total = $('.bounties-total'); + if ($total.text().contains(/A total of [0-9]+ listings were found/)) { + const num = $total.text().trim().split(' ')[3]; + if (newspaperDict['A total of {$} listings were found.']) { + $total.text(newspaperDict['A total of {$} listings were found.'] + .replace('{$}', num)); + } + } + // 列表 + $('.user-info-wrap div *').contents().each((i, e) => { + if (e.nodeType === 3) { + if (newspaperDict[e.nodeValue.trim()]) { + e.nodeValue = newspaperDict[e.nodeValue.trim()]; + } + } + }); + // claim + $('ul.bounties-list div.claim button').each((i, e) => { + if (newspaperDict[$(e).text().trim()]) { + $(e).text(newspaperDict[$(e).text().trim()]); + } + }); + $('ul.bounties-list div.claim a').each((i, e) => { + if (newspaperDict[$(e).text().trim()]) { + $(e).text(newspaperDict[$(e).text().trim()]); + } + }); + // 3选项框 + $('.add-bounties-wrap .name').contents().each((i, e) => { + if (e.nodeType === 3) { + if (newspaperDict[e.nodeValue.trim()]) { + e.nodeValue = newspaperDict[e.nodeValue.trim()]; + } + } else if (e.nodeType === 1) { + if (newspaperDict[$(e).text().trim()]) { + $(e).text(newspaperDict[$(e).text().trim()]); + } + } + }); + // 匿名选项 + const $anony = $('.choice-container label'); + if (newspaperDict[$anony.text().trim()]) { + $anony.text(newspaperDict[$anony.text().trim()]); + } + // 发钱按钮 + const $$symbol = $('span.input-money-symbol'); + if (sendCashDict[$$symbol.attr('title')]) { + $$symbol.attr('title', sendCashDict[$$symbol.attr('title')]) + } + // 10/10滑动 + const $slider_title = $('.slider-title'); + if ($slider_title.text().contains(/Quantity:/)) { + $slider_title.text($slider_title.text().replace('Quantity', '数量')); + } + // 价钱信息 + $('.confirm-bounties *').contents().each((i, e) => { + if (e.nodeType === 3) { + if (newspaperDict[e.nodeValue.trim()]) { + e.nodeValue = newspaperDict[e.nodeValue.trim()]; + } + } + }); + // 下单前确认对话 + $('.confirm-buttons *').contents().each((i, e) => { + if (e.nodeType === 3) { + if (newspaperDict[e.nodeValue.trim()]) { + e.nodeValue = newspaperDict[e.nodeValue.trim()]; + return; + } + switch (i) { + case 7: + case 10: { + if (e.nodeValue.contains(/[0-9] bounties/)) { + e.nodeValue = e.nodeValue.replace('bounties', '次') + } else if (e.nodeValue.contains(/with the reason: .+\?/)) { + e.nodeValue = e.nodeValue.replace('with the reason', '吗,悬赏原因') + } + break; + } + } + } + }); + // place + const $place = $('.place-buttons input'); + if (newspaperDict[$place.attr('value')]) { + $place.attr('value', newspaperDict[$place.attr('value')]); + } + // cancel + const $cancel = $('.place-buttons a.cancel'); + if (newspaperDict[$cancel.text().trim()]) { + $cancel.text(newspaperDict[$cancel.text().trim()]); + } + } + } + + newspaperTrans(); + newspaperOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); + return; + } + + // npc买房 estateagents + if (href.includes('estateagents.php')) { + titleTrans(); + contentTitleLinksTrans(); + $('div.estate-info div.title').each((i, e) => { + if (propertyDict[e.firstChild.nodeValue]) + e.firstChild.nodeValue = propertyDict[e.firstChild.nodeValue]; + }); + + return; + } + + // properties房屋页面 + if (href.includes('properties.php')) { + const isRent = window.location.href.indexOf('rent') >= 0; + // const isRentOrSell = isRent || window.location.href.indexOf('sell') >= 0; + // const isOption = window.location.href.indexOf('p=options') >= 0; + // const isExtension = window.location.href.indexOf('step=viewOfferExtension') >= 0; + const propertyOB = new MutationObserver(() => { + propertyOB.disconnect(); + titleTrans(); + contentTitleLinksTrans(); + propertyTrans(); + propertyOB.observe($('div.content-wrapper').get(0), {childList: true, subtree: true}); + }); + const propertyTrans = function propertyTrans() { + // 从玩家处租或买 + if (isRent || window.location.href.indexOf('sell') >= 0) { + // 黑框标题 + $('div.title-black span').each((i, e) => { + e.firstChild.nodeValue = '您想查看哪些房产?'; + }); + // 房屋汉化 + $('ul.info-cont label.marker-css').contents().each((i, e) => { + if (propertyDict[e.nodeValue]) + e.nodeValue = propertyDict[e.nodeValue]; + }); + //搜索按钮 + $('div.btn-search button').text('搜索'); + $('div.search-text a').text('搜索'); + // 表头信息 + $('div.users-list-title div').each((i, e) => { + if (propertyDict[$(e).text()]) + $(e).text(propertyDict[$(e).text()]); + }); + // 确认购买提示 + $('div[class="confirm-text"] span.question').each((i, e) => { + const propName = e.firstElementChild.innerText.trim().split(' ').slice(8).join(' '); + + const hasAnother = $(e).text().indexOf('another') > 0; + if (hasAnother) { + e.firstElementChild.firstChild.nodeValue = '你确定要'; + e.firstElementChild.firstChild.nodeValue += isRent ? '租用' : '购买'; + e.firstElementChild.childNodes[1].firstChild.nodeValue = '另一个'; + e.firstElementChild.childNodes[2].nodeValue = propertyDict[propName]; + } else { + e.firstElementChild.firstChild.nodeValue = '你确定要'; + e.firstElementChild.firstChild.nodeValue += isRent ? '租用' : '购买'; + e.firstElementChild.firstChild.nodeValue += propertyDict[propName]; + } + e.children[1].firstChild.nodeValue = '花费 '; + e.children[1].childNodes[2].nodeValue = isRent ? ' 租期 ' : '?'; + if (isRent) + e.children[1].childNodes[4].nodeValue = ' 天?'; + }); + + // 房屋详情表格 + $('div.info-block span.bold').each((i, e) => { + if (e.childElementCount === 2) { + /** + * + On + "Market" + Price + ":" + + */ + e.firstElementChild.firstChild.nodeValue = ''; + e.childNodes[2].nodeValue = '市场价'; + e.childNodes[3].firstChild.nodeValue = ''; + e.childNodes[4].nodeValue = ':'; + } else { + if (propertyDict[e.firstChild.nodeValue.trim()]) + e.firstChild.nodeValue = propertyDict[e.firstChild.nodeValue.trim()]; + } + }); + $('div.rental-period span.bold').each((i, e) => { + if (propertyDict[e.firstChild.nodeValue.trim()]) + e.firstChild.nodeValue = propertyDict[e.firstChild.nodeValue.trim()]; + }); + // 窄边 cost happy + $('span.title-laptop.bold').each((i, e) => { + if (propertyDict[$(e).text().trim()]) + $(e).text(propertyDict[$(e).text().trim()]); + }); + // modification + $('div.title.bold.left').each((i, e) => { + if (propertyDict[e.firstChild.nodeValue]) + e.firstChild.nodeValue = propertyDict[e.firstChild.nodeValue]; + }); + + return; + } + // 房屋选项 + if (window.location.href.indexOf('p=options') >= 0) { + // 页面的黑框标题 + $('div.content-wrapper div.title-black').each((i, e) => { + if (propertyDict[$(e).text().trim()]) + $(e).text(propertyDict[$(e).text().trim()]); + }); + // 所有li内容 + // $('div.content-wrapper div.customize-opt li').find('*') + // .contents().each((i,e)=>{ + // if(e.nodeType!==3)return;log(e) + // }); + return; + } + // 房屋详情 + if (window.location.href.indexOf('p=propertyinfo') >= 0) { + return; + } + // 延期、合同 + if (window.location.href.indexOf('step=viewOfferExtension') >= 0) { + return; + } + // 自己的所有房产 页面 + { + // 顶部3标题 + $('ul.property-tabs a.ui-tabs-anchor div').contents().each((i, e) => { + if (propertyDict[e.nodeValue]) { + e.nodeValue = propertyDict[e.nodeValue]; + } + }); + // 图片下的描述部分 + $('ul.properties-list div.image-description').find('*') + .contents().each((i, e) => { + if (e.nodeType !== 3) return; + if (!propertyDict[e.nodeValue.trim()]) return; + e.nodeValue = propertyDict[e.nodeValue.trim()]; + }); + // 图片下的按钮的title浮动框文字 + $('div#properties-page-wrap a[title]').each((i, e) => { + if (propertyDict[$(e).attr('title')]) + $(e).attr('title', propertyDict[$(e).attr('title')]); + }); + } + }; + + propertyTrans(); + propertyOB.observe($('div.content-wrapper').get(0), {childList: true, subtree: true}); + return; + } + + // 通知页面 + if (href.includes('events.php')) { + const ob = new MutationObserver(() => { + ob.disconnect(); + titleTrans(); + contentTitleLinksTrans(); + eventsTrans(); + ob.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); + }); + eventsTrans(); + ob.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); + return; + // let events; + // const eventMutation = new MutationObserver(() => { + // eventMutation.disconnect(); + // // events = $('span.mail-link'); + // // eventsTrans(events); + // eventsTrans(); + // eventMutation.observe($('div#events-main-wrapper')[0], {childList: true, subtree: true}); + // }); + // + // //初始化中内容未加载 + // let eventInterval = setInterval(() => { + // // events = $('span.mail-link'); + // // if (events.length === 0) { + // // return; + // // } + // clearInterval(eventInterval); + // eventMutation.observe($('div#events-main-wrapper')[0], {childList: true, subtree: true}); + // eventsTrans(events); + // }, 1000); + } + + // awards.php + if (href.includes('awards.php')) { + const awOB = new MutationObserver(() => { + awOB.disconnect(); + awTrans(); + awOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); + }); + const awTrans = function awTrans() { + titleTrans(); + contentTitleLinksTrans(); + // 顶部的3个分类 Honors (106) Medals (44) Merits (3) + $('div.content-wrapper a.ui-tabs-anchor span.bold').contents().each((i, e) => { + if (e.nodeType !== 3) return; + if (awDict[e.nodeValue.trim()]) + e.nodeValue = awDict[e.nodeValue.trim()]; + }); + // 分类标题下的描述 + $('div.awards-msg').contents().each((i, e) => { + // 文字节点 + if (e.nodeType === 3) { + if (awDict[e.nodeValue.trim()]) + e.nodeValue = awDict[e.nodeValue.trim()]; + } + // 子节点 + else if (e.nodeType === 1) { + if (awDict[$(e).text().trim()]) + $(e).text(awDict[$(e).text().trim()]); + else if ($(e).text().indexOf('medals') >= 0) + $(e).text($(e).text().replace('medals', awDict['medals'])); + else if ($(e).text().indexOf('honors') >= 0) + $(e).text($(e).text().replace('honors', awDict['honors'])); + } + }); + // 荣誉的描述 + $('div#awards-tab-menu a[data-title]').each((i, e) => { + const desc = $(e).attr('data-title').split(' ')[0]; + if (awDict[desc]) + $(e).attr('data-title', $(e).attr('data-title').replace(desc, awDict[desc])); + }); + // 改变荣誉条时的提示 + $('div#honors div.msg').each((i, e) => { + if (awDict[$(e).text().trim()]) + $(e).text(awDict[$(e).text().trim()]); + }); + // 改变荣誉条时的提示按钮 change + $('div#honors div.confirm-msg button').each((i, e) => { + if (awDict[$(e).text().trim()]) + $(e).text(awDict[$(e).text().trim()]); + }); + // 改变荣誉条时的提示按钮 cancel + $('div#honors div.confirm-msg a.cancel').each((i, e) => { + if (awDict[$(e).text().trim()]) + $(e).text(awDict[$(e).text().trim()]); + }); + // 天赋页面 Available Merits: x Merits Used: x + $('div.awards-msg p').contents().each((i, e) => { + if (e.nodeType === 3) + if (awDict[e.nodeValue.trim()]) + e.nodeValue = e.nodeValue.replace(e.nodeValue.trim(), awDict[e.nodeValue.trim()]); + }); + // 勋章下 即将解锁的勋章框标题 天赋加点的表头标题 + $('div.title-black').contents().each((i, e) => { + // 勋章下 即将解锁的勋章框标题 + if (e.nodeType === 1) { + if (awDict[$(e).text().trim()]) + $(e).text(awDict[$(e).text().trim()]); + } + // 天赋加点的表头标题 + else if (e.nodeType === 3) { + if (awDict[e.nodeValue.trim()]) + e.nodeValue = awDict[e.nodeValue.trim()]; + } + }); + // 荣誉和勋章的左边栏分类选择菜单 + $('div.tab-menu-cont li.ui-state-default a').each((i, e) => { + if (awDict[$(e).text().trim()]) + $(e).text(awDict[$(e).text().trim()]); + }); + // 天赋点名字 + $('ul#merits-list span.name').each((i, e) => { + if (awDict[$(e).text().trim()]) + $(e).text(awDict[$(e).text().trim()]); + }); + // 天赋点短描述 + $('ul#merits-list span.desc span[class^="t-"]').each((i, e) => { + // const slash = $(e).attr('class') === 't-show' ? '- ' : ''; + const isShow = $(e).attr('class') === 't-hide'; + const key = isShow ? $(e).text().slice(2) : $(e).text(); + if (awDict[key]) + $(e).text((isShow ? '- ' : '') + awDict[key]); + }); + // 天赋点展开详细描述与确认 + $('ul#merits-list div.msg').contents().each((i, e) => { + // x merit(s) + if (e.nodeType === 1) { + const spl = $(e).text().split(' '); + if (awDict[spl[1]]) + $(e).text(spl[0] + ' ' + awDict[spl[1]]); + } + // 文字片段 + else if (e.nodeType === 3) { + if (awDict[e.nodeValue.trim()]) { + e.nodeValue = awDict[e.nodeValue.trim()] + ''; + return; + } + const spl = e.nodeValue.trim().split('\n'); + // 未升级完成 + if (spl.length === 3) { + const upgradeName = spl[1].slice(5, -9); + const on = spl[0]; + const upgrade = spl[1].slice(-8); + const desc = spl[2]; + if (awDict[on] && awDict[upgrade] && awDict[upgradeName] && awDict[desc]) + e.nodeValue = ' ' + awDict[on] + awDict[upgradeName] + + awDict[upgrade] + awDict[desc]; + } + // 升级完成 + else if (spl.length === 1) { + const upgraded = e.nodeValue.trim().slice(0, 60); + const desc = e.nodeValue.trim().slice(61); + if (awDict[upgraded]) e.nodeValue = awDict[upgraded]; + if (awDict[desc]) e.nodeValue += awDict[desc]; + } + } + }); + // spend cancel按钮 + $('ul#merits-list div.confirm-cont a').each((i, e) => { + if (awDict[$(e).text().trim()]) $(e).text(awDict[$(e).text().trim()]); + }); + }; + awTrans(); + awOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); + return; + } + + // preferences设置 + if (href.contains(/preferences\.php/)) { + const $$ = $('.content-wrapper'); + const OB = new MutationObserver(() => { + OB.disconnect(); + titleTrans(); + contentTitleLinksTrans(); + trans(); + OB.observe($$.get(0), { + characterData: true, + attributes: true, + subtree: true, + childList: true + }); + }); + const trans = () => { + // 黑框标题 + const $black_title = $('.title-black'); + if (tornSettingsDict[$black_title.text().trim()]) { + $black_title.text(tornSettingsDict[$black_title.text().trim()]); + } + // 电脑版左边导航菜单 + const $nav = $('.content-wrapper a.ui-tabs-anchor'); + $nav.each((i, e) => { + if (tornSettingsDict[$(e).text().trim()]) { + $(e).text(tornSettingsDict[$(e).text().trim()]); + } + }); + if (window.location.href.contains(/tab=api/)) { + // 描述 + const $api_desc = $('.content-wrapper p[class^="apiDescription___"]'); + if (tornSettingsDict[$api_desc.text().slice(0, 50)]) { + $api_desc.text(tornSettingsDict[$api_desc.text().slice(0, 50)]); + } + // 添加按钮 + const $add_btn = $('button[class^="addKey___"] span'); + if (tornSettingsDict[$add_btn.text().trim()]) { + $add_btn.text(tornSettingsDict[$add_btn.text().trim()]); + } + // new keys name + const $new_keys_name = $('input[placeholder="New key\'s name"]'); + if (tornSettingsDict[$new_keys_name.attr('placeholder')]) { + $new_keys_name.attr('placeholder', tornSettingsDict[$new_keys_name.attr('placeholder')]); + } + // api类型 + const $key_type = $('div[class*="typesDropdown___"] button.down'); + if (tornSettingsDict[$key_type.text().trim()]) { + $key_type.text(tornSettingsDict[$key_type.text().trim()]); + } + // api类型选择框 + const $type_down = $('div[class*="typesDropdown___"] div.down li'); + $type_down.each((i, e) => { + if (tornSettingsDict[$(e).text().trim()]) { + $(e).text(tornSettingsDict[$(e).text().trim()]); + } + }); + // return; + } + }; + trans(); + OB.observe($$.get(0), { + characterData: true, + attributes: true, + subtree: true, + childList: true + }); + return; + } + + // 展柜 + if (href.contains(/displaycase\.php/)) { + const $page_wrapper = document.querySelector('#display-page-wrap'); + initOB($page_wrapper, { + subtree: true, + attributes: true, + childList: true + }, + () => { + // 标题和右边的链接 + titleTrans(); + // 右上角返回按钮 + const $back_to_profile = $page_wrapper.querySelector('#back'); + if ($back_to_profile) { + const spl = $back_to_profile.innerText.split(/('s |s' )/); + if (spl.length === 3 && spl[2] === 'Profile') { + $back_to_profile.innerText = `${spl[0]}的个人资料`; + } + } + const $display_cabinet = $page_wrapper.querySelector('.display-cabinet'); + if ($display_cabinet) { + // 物品名 + const $item_name = $display_cabinet.querySelectorAll('div.b-item-name span:nth-of-type(2)'); + $item_name.forEach((e) => { + if (itemNameDict[e.innerText]) { + e.innerText = itemNameDict[e.innerText]; + } + }); + // 展开详细框 + const $show_item_info = $display_cabinet.querySelector('.show-item-info'); + showItemInfoTrans($show_item_info); + } + }); + return; + } + + // 升级页面 + if (href.includes('level2.php')) { + } + + // 医院页面 + if (href.includes("hospitalview.php")) { + const hospitalOB = new MutationObserver(hosOBInit); + + function hosOBInit() { + hospitalOB.disconnect(); + hospTrans(); + hospitalOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); + } + + function hospTrans() { + titleTrans(); + contentTitleLinksTrans(); + + // 顶部提示信息 + $('div[class^="msg right-round"]').contents().each((i, e) => (hosDict[e.nodeValue.trim()]) && (e.nodeValue = hosDict[e.nodeValue.trim()])); + + //玩家列表标题 + $('div[class^="users-list-title title-black top-round m-top10"] span').contents().each((i, e) => { + if (e.nodeValue && hosDict[e.nodeValue.trim()]) { + e.nodeValue = e.nodeValue.replace(e.nodeValue, hosDict[e.nodeValue.trim()]); + } + }) + + //玩家列表住院理由 + $('ul[class^="user-info-list-wrap"] span[class^="reason"]').each((i, e) => { + let reasonStr = $(e).get(0).childNodes[1].nodeValue.trim(); + + if (hosDict[reasonStr]) { + $(e)[0].childNodes[1].nodeValue = hosDict[reasonStr]; + } else if (reasonStr.indexOf("Crashed") >= 0) { + $(e)[0].childNodes[1].nodeValue = reasonStr + .replace("Crashed her", hosDict["Crashed her"]) + .replace("Crashed his", hosDict["Crashed his"]); + } else { + switch (reasonStr) { + case "Attacked by": + $(e)[0].childNodes[1].nodeValue = hosDict["general"]; + $(e).append(" 攻击"); + break; + case "Hospitalized by": + $(e)[0].childNodes[1].nodeValue = hosDict["general"]; + $(e).append(" 殴打并送入医院"); + break; + case "Mugged by": + $(e)[0].childNodes[1].nodeValue = hosDict["general"]; + $(e).append(" 抢劫"); + break; + } + } + }) + } + + hospTrans(); + hospitalOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); + return; + } + + // 帮派页面 + if (href.includes("actions.php")) { + const factionOB = new MutationObserver(factionOBInit); + + function factionOBInit() { + factionOB.disconnect(); + factionTrans(); + factionOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); + } + + const factionDict = { + "INFO": "信息", + "TERRITORY": "地盘", + "RANK": "名次", + "CRIMES": "组织犯罪", + "UPGRADES": "升级", + "ARMORY": "军械库", + "CONTROLS": "控制面板", + "FACTION": "帮派", + "YOUR FACTION IS NOT IN A WAR": "你的帮派没有处于战争状态", + "TIER": "级别", + "RESPECT": "声望", + "No active chain": "暂无攻击链", + "Main News": "主要消息", + "Attacking": "攻击", + "Funds": "资金流动", + "Armory": "军械库", + "Crimes": "组织犯罪", + "Membership": "成员资格", + "has claimed sovereignty of": "", + "has abandoned": "放弃了地盘", + "Achieved a chain of": "达成了连击链值", + "and": "和", + "respect [": "点声望 [", + "deposited ${$1}": "存放了${$1}", + "Leadership was transferred to": "帮派领导权被移交给了 ", + "Someone mugged": "有人抢劫了 ", + "hospitalized": " 暴打了 ", + "mugged": " 抢劫了 ", + "attacked": " 攻击了 ", + "but lost": " 但是输了", + "Someone attacked": "有人攻击了 ", + "Someone hospitalized": "有人暴打了 " + } + + function factionTrans() { + titleTrans(); + contentTitleLinksTrans(); + + //帮派大标题 + $('span[class^="tab-name"]').each((i, e) => { + if (factionDict[$(e).text().trim()]) { + $(e).text(factionDict[$(e).text().trim()]); + } + }) + + //帮派战争状态 + $('div[class^="f-msg"]').contents().each((i, e) => { + let word2Trans = $(e).text().trim().split(":")[0]; + if (word2Trans && factionDict[word2Trans]) { + $(e).text($(e).text().replace(word2Trans, factionDict[word2Trans])); + } + }) + + //攻击链盒 + $('div[class^="chain-box"]').contents().each((i, e) => { + if (factionDict[$(e).text().trim()]) { + $(e).text(factionDict[$(e).text().trim()]); + } + }) + + //帮派消息类别 + $('div[class^="newsHeader"]').contents().each((i, e) => { + if (factionDict[$(e).text().trim()]) { + $(e).text(factionDict[$(e).text().trim()]); + } + }) + //帮派主要消息日志 + $('button[class^="tab"] ').each((i, e) => { + if ($(e).attr('class').indexOf("active") >= 0) { + log($(e).text()); + switch ($(e).text().trim()) { + case "主要消息": + $('ul[class^="news-list"] span[class^="info"]').contents().each((i, u) => { + if (factionDict[$(u).text().trim()]) { + u.nodeValue = u.nodeValue.replace($(u).text().trim(), factionDict[$(u).text().trim()]); + } + }) + break; + case "攻击": + $('ul[class^="news-list"] span[class^="info"]').find('*').contents().each((i, u) => { + log($(u).text().trim()) + if (factionDict[$(u).text().trim()]) { + u.nodeValue = factionDict[$(u).text().trim()]; + } + }) + break; + case "资金流动": + $('ul[class^="news-list"] span[class^="info"]').contents().each((i, u) => { + if (u.nodeValue) { + u.nodeValue = u.nodeValue.replace("deposited", "存放了"); + } + }) + break; + } + } + }) + // //帮派主要消息日志 + // $('ul[class^="news-list"] span[class^="info"]').contents().each((i, e) => { + // if (factionDict[$(e).text().trim()]) { + // e.nodeValue = e.nodeValue.replace($(e).text().trim(), factionDict[$(e).text().trim()]); + // } + // }) + + } + + factionTrans(); + factionOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); + return; + } + + // pc电脑 + if (href.contains(/pc\.php/)) { + const $$ = $('.content-wrapper'); + const OB = new MutationObserver(() => { + OB.disconnect(); + titleTrans(); + contentTitleLinksTrans(); + trans(); + OB.observe($$.get(0), { + characterData: true, + attributes: true, + subtree: true, + childList: true + }); + }); + const trans = () => { + // 黑框 + const $black_title = $('div.title-black'); + if (pcDict[$black_title.text().trim()]) { + $black_title.text(pcDict[$black_title.text().trim()]); + } + }; + trans(); + OB.observe($$.get(0), { + characterData: true, + attributes: true, + subtree: true, + childList: true + }); + return; + } + + // 日历 + if (href.contains(/calendar\.php/)) { + const $root = document.querySelectorAll('#calendar-root'); + $root.forEach(el => { + initOB(el, {childList: true, subtree: true}, () => { + // 页标题 + const $h4_title = el.querySelectorAll('h4[class^="title___"]'); + titleTransReact($h4_title); + // 页标题右侧链接 + const $link_title = el.querySelectorAll('div[class^="linksContainer___"] span[class^="linkTitle___"]'); + contentTitleLinksTransReact($link_title); + // 月标题 + const $month_title = el.querySelectorAll('div[class^="monthName___"]'); + $month_title.forEach(e => { + if (calDict[e.innerText.trim()]) e.innerText = calDict[e.innerText.trim()]; + }); + }); + }); + return; + } + + // itemuseparcel.php + + // 圣诞小镇 + if (href.contains(/christmas_town\.php/)) { + let $root = document.querySelector('#christmastownroot'); + const $title_wrapper = $root.querySelector('div[class^="appHeaderWrapper___"]'); + // 标题和右边的链接 + initOB($title_wrapper, {childList: true, subtree: true}, () => { + titleTransReact(); + contentTitleLinksTransReact(); + }); + } +} \ No newline at end of file diff --git a/src/init.ts b/src/init.ts index 77e0687..c9acfb8 100644 --- a/src/init.ts +++ b/src/init.ts @@ -12,7 +12,8 @@ import WindowActiveState from "./func/utils/WindowActiveState"; import addStyle from "./func/utils/addStyle"; // 初始化方法,获取必要全局参数 -export default function init(glob: Global) { +export default function init(): Global { + let glob: Global = {}; glob.window = window; window.WHPARAMS = glob; let UWCopy = null; @@ -40,7 +41,7 @@ export default function init(glob: Global) { Notification.requestPermission().then(); } - // 扩展String正则方法 + // 扩展正则方法 String.prototype.contains = function (keywords) { let that: string = this; if ('string' === typeof keywords) { @@ -82,6 +83,8 @@ export default function init(glob: Global) { // 抢啤酒 glob.beer = BuyBeer(); + + // 当前的弹出窗口 glob.popup_node = null; // 当窗口关闭时关闭所有还存在的通知 @@ -100,6 +103,8 @@ export default function init(glob: Global) { // 记录当前窗口唯一id glob.isWindowActive = WindowActiveState(); + glob.href = window.location.href; + addStyle(` .wh-hide{display:none;} #wh-trans-icon{ @@ -247,4 +252,5 @@ cursor:pointer; } `); + return glob; } \ No newline at end of file diff --git a/src/interface/GlobalVars.ts b/src/interface/GlobalVars.ts index 563d60c..37aaed7 100644 --- a/src/interface/GlobalVars.ts +++ b/src/interface/GlobalVars.ts @@ -2,8 +2,12 @@ import Device from "../enum/Device"; import {BeerMonitorLoop} from "../func/utils/BuyBeer"; export default interface Global { + href?: string; + $zhongNode?: MyHTMLElement; + isWindowActive?(): boolean; - popup_node?: Element; + + popup_node?: MyHTMLElement; beer?: BeerMonitorLoop; notifies?: NotifyWrapper; priceWatcher?: { status: boolean }; @@ -16,5 +20,5 @@ export default interface Global { version?: string; window?: Window; UWCopy?: Window & typeof globalThis; - startTimestamp: number; + // startTimestamp: number; } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 2f1eea5..87a2e3b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,23 @@ import userscript from "./userscript"; -import Global from "./interface/GlobalVars"; +import zhongIcon from "./zhongIcon"; +import init from "./init"; +import getWhSettingObj from "./func/utils/getWhSettingObj"; +import translateMain from "./func/translate/translateMain"; -const glob: Global = { - startTimestamp: -1, -}; +(function main() { + let started = new Date().getTime(); -userscript(glob); \ No newline at end of file + if (document.title.toLowerCase().includes('just a moment')) return; + + let glob = init(); + + zhongIcon(glob); + + if (getWhSettingObj()['transEnable']) translateMain(glob.href); + + userscript(); + + let runTime = new Date().getTime() - started; + glob.$zhongNode.initTimer.innerHTML = `助手加载时间 ${runTime}ms`; +}) +(); \ No newline at end of file diff --git a/src/userscript.ts b/src/userscript.ts index 8558781..3c263a9 100644 --- a/src/userscript.ts +++ b/src/userscript.ts @@ -45,16 +45,8 @@ import UserScriptEngine from "./enum/UserScriptEngine"; import getPlayerInfo from "./func/utils/getPlayerInfo"; import Global from "./interface/GlobalVars"; -export default function userscript(glob: Global): void { - glob.startTimestamp = Date.now(); - if (document.title.toLowerCase().includes('just a moment')) return; - - init(glob); - let {version, isIframe, PDA_APIKey, isPDA, player_info, fstock, notifies} = glob; - - const href = window.location.href; - // 开启翻译 - transToZhCN(href, getWhSettingObj()['transEnable']); +export default function userscript(): void { + let {version, isIframe, PDA_APIKey, isPDA, player_info, fstock, notifies} = window.WHPARAMS; // 啤酒提醒 不终止 if (getWhSettingObj()['_15Alarm']) beer.start(); @@ -2755,2176 +2747,6 @@ margin: 0 0 3px; return `${task ? '任务要求:' + task : '暂无,请联系Woohoo'}${hint ? '
提示:' + hint : ''}`; } - /* - 展开物品详情 - */ - function showItemInfoTrans(dom = document.querySelector('.show-item-info')) { - if (dom) { - const $item_info = dom.querySelector('span.info-msg'); - if ($item_info) { - // tt插件 - const is_tt_modified = !!$item_info.querySelector('.tt-modified'); - if (is_tt_modified) { - console.warn(is_tt_modified) - } - // 物品名 - const $item_name = $item_info.querySelector('span.bold'); - // 去除物品名的the - const the_removed = $item_name.innerText.trim().slice(4); - // 物品的类别 - const $item_type = $item_name.nextSibling; - // 绿字 物品效果 - const $item_effect = $item_info.querySelector('div.item-effect'); - if (itemNameDict[the_removed]) { - $item_name.innerText = `${itemNameDict[the_removed]}(${the_removed})`; - } - if (itemTypeDict[$item_type.nodeValue.trim()]) { - $item_type.nodeValue = itemTypeDict[$item_type.nodeValue.trim()]; - } - if ($item_effect && itemEffectDict[$item_effect.innerText.trim()]) { - $item_effect.innerText = itemEffectDict[$item_effect.innerText.trim()]; - } - } - // 下方的表格 - const $info_table_title = dom.querySelectorAll('div.title'); - $info_table_title.forEach((e) => { - if (itemPageDict[e.innerText.trim()]) { - e.innerText = itemPageDict[e.innerText.trim()]; - } - }); - } - } - - /* - ob - */ - function initOB(dom = document, opt = {}, func = doNothing, dev = false, once = false) { - //let count = -1; - if (dev) { - const mo = new MutationObserver((mutation) => { - //count++; - log(mutation) - mo.disconnect(); - func(); - if (!once) { - mo.observe(dom, opt) - } - }); - func(); - mo.observe(dom, opt); - } else { - //count++; - const mo = new MutationObserver(() => { - mo.disconnect(); - func(); - if (!once) mo.observe(dom, opt) - }); - func(); - mo.observe(dom, opt) - } - } - - - - - // bool 返回当前是否dev状态 - function isDev() { - try { - return getWhSettingObj()['isDev'] || false; - } catch (e) { - console.error(`[wh] dev状态错误 ${e}`); - return false; - } - } - - /** - * 弹出窗口 - * @param {String} innerHTML 内容html string - * @param {String} title 弹窗标题 - * @returns {null|Element} - */ - function popupMsg(innerHTML, title = '芜湖助手') { - if (popup_node) popup_node.close(); - const chatRoot = document.querySelector('#chatRoot'); - chatRoot.classList.add('wh-hide'); - const popup = document.createElement('div'); - popup.id = 'wh-popup'; - popup.innerHTML = `
-

${title}

-
${innerHTML}
-
`; - document.body.append(popup); - const rt = popup.querySelector('#wh-popup-cont'); - rt.close = function () { - popup.remove(); - chatRoot.classList.remove('wh-hide'); - } - popup.addEventListener('click', e => { - e.stopImmediatePropagation(); - if (e.target === popup) rt.close(); - }); - popup_node = rt; - return rt; - } - - // 翻译 - function transToZhCN(href, onoff) { - if (!onoff) return; - - // 时分秒转换 - String.prototype.replaceHMS = function replaceHMS() { - return this.replace('and', '') - .replace('days', '天') - .replace('days', '天') - .replace('hours', '小时') - .replace('hour', '小时') - .replace('minutes', '分钟') - .replace('minute', '分钟') - .replace('seconds', '秒钟') - .replace('second', '秒钟'); - }; - - // 数词转换 a an some - String.prototype.numWordTrans = function numWordTrans() { - return this.replace(/\ban\b/, '1 个') - .replace(/\ba\b/, '1 个') - .replace(/\bsome\b/, '1 个') - .replace(/([0-9])x\b/, '$1 个'); - }; - - // 边栏 - let sidebarTimeOut = 60; - const sidebarInterval = setInterval(() => { - // 60秒后取消定时 - if ($('div[class^="sidebar"]').length === 0) { - sidebarTimeOut--; - if (sidebarTimeOut < 0) { - clearInterval(sidebarInterval); - } - return; - } - // 边栏块标题 - $('h2[class^="header"]').each((i, e) => { - if (!sidebarDict[e.firstChild.nodeValue]) return; - e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue]; - }); - // 边栏人物名字 - $('span[class^="menu-name"]').each((i, e) => { - e.firstChild.nodeValue = '名字:'; - }); - // 钱 等级 pt 天赋点 - $('p[class^="point-block"]').each((i, e) => { - if (sidebarDict[e.firstChild.firstChild.nodeValue]) - e.firstChild.firstChild.nodeValue = sidebarDict[e.firstChild.firstChild.nodeValue]; - }); - // 4条 状态条 - $('p[class^="bar-name"]').each((i, e) => { - if (sidebarDict[e.firstChild.nodeValue]) - e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue]; - }); - // 边栏菜单 - $('span[class^="linkName"]').each((i, e) => { - if (sidebarDict[e.firstChild.nodeValue]) - e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue]; - }); - // [use]按钮 - if (document.querySelector('#pointsMerits')) - $('#pointsMerits')[0].firstChild.nodeValue = '[使用]'; - if (document.querySelector('#pointsPoints')) - $('#pointsPoints')[0].firstChild.nodeValue = '[使用]'; - if (document.querySelector('#pointsLevel')) - $('#pointsLevel')[0].firstChild.nodeValue = '[升级]'; - - // 手机 区域菜单 - $('div[class*="areas-mobile"] span:nth-child(2)').contents().each((i, e) => { - //log(e); - if (sidebarDict[e.nodeValue]) - e.nodeValue = sidebarDict[e.nodeValue]; - }); - - clearInterval(sidebarInterval); - }, 1000); - - // header - if (document.querySelector('div#header-root')) { - const headerOB = new MutationObserver(_ => { - headerOB.disconnect(); - headerTrans(); - headerOB.observe($('div#header-root')[0], {childList: true, subtree: true, attributes: true}); - }); - - const headerTrans = function headerTrans() { - // 搜索内容下拉框中的文字 已选中 - if (headerDict[$('div.find button.toggler.down').text()]) - $('div.find button.toggler.down').text(headerDict[$('div.find button.toggler.down').text()]); - // pc端 搜索下拉框点击后的搜索类型文字 - $('div.find li.item').each((i, e) => { - if (headerDict[$(e).text()]) - $(e).text(headerDict[$(e).text()]); - }); - // 手机端 搜索下拉框点击后的搜索类型文字 - $('li[class^="search-type-"] label').each((i, e) => { - if (headerDict[$(e).text()]) - $(e).text(headerDict[$(e).text()]); - }); - // 搜索框placeholder - if (headerDict[$('input[class^="searchInput"]').attr('placeholder')]) - $('input[class^="searchInput"]').attr('placeholder', - headerDict[$('input[class^="searchInput"]').attr('placeholder')]); - // 高级搜索框 search by - if (headerDict[document.querySelector('div#header-root legend.title').innerText]) - $('div#header-root legend.title').text(headerDict[$('div#header-root legend.title').text()]); - // 高级搜索框的条件 左 键 - $('ul.advancedSearchFormBody label.label').each((i, e) => { - if (headerDict[$(e).text()]) - $(e).text(headerDict[$(e).text()]); - }); - // 高级搜索框的已选中 - $('ul.advancedSearchFormBody div.select-wrapper button.toggler.down').each((i, e) => { - // log($(e).text()) - if (headerDict[$(e).text().trim()]) - $(e).text(headerDict[$(e).text().trim()]); - else if (propertyDict[$(e).text().trim()]) - $(e).text(propertyDict[$(e).text().trim()]); - }); - // 高级搜索的下拉选项 - $('ul.advancedSearchFormBody li.item').each((i, e) => { - if (headerDict[$(e).text()]) - $(e).text(headerDict[$(e).text()]); - else if (propertyDict[$(e).text()]) - $(e).text(propertyDict[$(e).text()]); - }); - // 高级搜索的"Not" - $('ul.advancedSearchFormBody label.search-condition-not').each((i, e) => { - if (headerDict[$(e).text()]) - $(e).text(headerDict[$(e).text()]); - }); - // 高级搜索的"to" - $('ul.advancedSearchFormBody label[for*="To"]').each((i, e) => { - if (headerDict[$(e).text()]) - $(e).text(headerDict[$(e).text()]); - }); - // 高级搜索的reset search按钮 - $('form.form-search-extend div.bottom button').each((i, e) => { - if (headerDict[$(e).text()]) - $(e).text(headerDict[$(e).text()]); - }); - // log按钮“view log” - const $view_log = $('div.recentHistory a[class^="link"] span[class^="text"]') - if (headerDict[$view_log.text().trim()]) - $view_log - .text(headerDict[$view_log.text().trim()]); - // 点击头像打开的菜单 - $('ul.settings-menu span').each((i, e) => { - if (headerDict[$(e).text()] && e.childNodes.length === 1) - $(e).text(headerDict[$(e).text()]); - else if (e.childNodes.length === 3) - if (headerDict[e.firstChild.nodeValue]) - e.firstChild.nodeValue = headerDict[e.firstChild.nodeValue]; - }); - }; - headerTrans(); - headerOB.observe($('div#header-root')[0], {childList: true, subtree: true, attributes: true}); - } - - // chatbox - if (document.querySelector('div#chatRoot')) { - const chatOB = new MutationObserver(_ => { - chatOB.disconnect(); - chatTrans(); - chatOB.observe($('div#chatRoot').get(0), {childList: true, subtree: true, attributes: true}); - }); - const chatTrans = function chatTrans() { - // 聊天框的标题 - $('div#chatRoot div[class^="chat-box-title"] span[class^="name"]').each((i, e) => { - if (chatDict[$(e).text().trim()]) - $(e).text(chatDict[$(e).text().trim()]); - }); - // 聊天设置的左边label - $('div[class^="chat-settings-opts"] div[class*="label"]').each((i, e) => { - if ($(e).next().children('div.rc-slider').length > 0) { - // 高度和宽度有响应式的% - if (chatDict[$(e).text().split(' ')[0]]) { - $(e).text($(e).text().replace($(e).text().split(' ')[0], chatDict[$(e).text().split(' ')[0]])); - } - return; - } - if (chatDict[$(e).text().trim()]) - $(e).text(chatDict[$(e).text().trim()]); - }); - // 选项下拉栏 - $('div[class^="dropdown-root"]').find('*').contents().each((i, e) => { - if (e.nodeType !== 3) return; - if (chatDict[e.nodeValue]) - e.nodeValue = chatDict[e.nodeValue]; - }); - // 设置的两个选项 - $('label[class^="privacy-label"]').each((i, e) => { - if (chatDict[$(e).text().trim()]) - $(e).text(chatDict[$(e).text().trim()]); - }); - // people中的5个分类 faction friend... - $('ul[class^="type-list"] li a').each((i, e) => { - if (chatDict[$(e).text().trim()]) - $(e).text(chatDict[$(e).text().trim()]); - }); - // people中的列表添加框placeholder - $('div.ac-wrapper input.ac-search').each((i, e) => { - if (chatDict[$(e).attr('placeholder')]) - $(e).attr('placeholder', chatDict[$(e).attr('placeholder')]); - }); - // - if (eventsDict[$('div#chatRoot div[class^="overview"] > div > div:nth-child(2)').text().trim()]) { - $('div#chatRoot div[class^="overview"] > div > div:nth-child(2)') - .text( - eventsDict[document.querySelector('div#chatRoot div[class^="overview"] > div > div:nth-child(2)').innerText.trim()] - ); - } - }; - chatTrans(); - chatOB.observe($('div#chatRoot').get(0), {childList: true, subtree: true, attributes: true}); - } - - // 搜索玩家的4个分类按钮 - const playerSearchBoxTrans = function playerSearchBoxTrans() { - const opt = { - childList: true, - subtree: true, - }; - const psbtOB = new MutationObserver(mutation => { - const $people_cat = $('ul.ac-options li a'); - psbtOB.disconnect(); - mutation.forEach((e) => { - if (e.target.className === 'ac-wrapper') { - $people_cat.each((i, e) => { - if (chatDict[$(e).text().trim()]) - $(e).text(chatDict[$(e).text().trim()]); - }); - } - }) - psbtOB.observe(document.body, opt); - }); - psbtOB.observe(document.body, opt); - } - playerSearchBoxTrans(); - - // 飞行页面 - if (href.includes('index.php') && - !!document.querySelector('div.travelling h4')) { - const travelOB = new MutationObserver(travelOBInit); - - function travelOBInit() { - travelOB.disconnect(); - travelTrans(); - travelOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); - } - - function travelTrans() { - titleTrans(); - contentTitleLinksTrans(); - - // 气泡 - if (tipsDict[document.querySelector('div.inner-popup').innerText.trim()]) - $('div.inner-popup').text(tipsDict[$('div.inner-popup').text().trim()]); - // Remaining Flight Time - - $('div.destination-title span').contents().each((i, e) => { - if (e.childNodes.length !== 0) return; - if (!e.nodeValue) return; - if (travelingDict[e.nodeValue.trim()]) - e.nodeValue = travelingDict[e.nodeValue.trim()]; - }); - // torntools扩展插件落地时间 - if (document.querySelector('div.tt-landing-time span.description').innerText.split(' ')[0] === 'Landing') { - const landingTime = $('div.tt-landing-time span.description').text().slice(11, 19); - $('div.tt-landing-time span.description').text('于 ' + landingTime + ' 降落'); - } - } - - travelTrans(); - travelOB.observe(document.querySelector('div.content-wrapper'), {childList: true, subtree: true}); - } - - // 主页 - if (href.contains(/index\.php/) && document.querySelector('h4#skip-to-content').innerText.contains(/Home/)) { - titleTrans(); - contentTitleLinksTrans(); - // 主页黑框标题文字翻译 - $('h5.box-title').each((i, e) => { - if (!homeDict[e.firstChild.nodeValue]) return; - // 翻译最近5条通知 - if (e.firstChild.nodeValue === 'Latest Events') { - //homeEvents = $(e).parent().next().find('span'); - eventsTrans($(e).parent().next().find('span')); - } - // 翻译最近5个攻击 - else if (e.firstChild.nodeValue === 'Latest Attacks') { - $(e).parent().next().find('span').each(function () { - let nodes = $(this)[0].childNodes; - nodes.forEach((v, i) => { - if (v.nodeValue !== null) { - let waitToTsf = v.nodeValue.toString().indexOf(" "); - let words = v.nodeValue.replace("\n", "").toString().split(" "); - words.forEach((word, j) => { - if (attackDict.hasOwnProperty(word)) { - if (word === "Someone") { - $(this)[0].childNodes[i].nodeValue = $(this)[0].childNodes[i].nodeValue.replace(" ", ""); - } - let change = $(this)[0].childNodes[i].nodeValue.replace(word, attackDict[word]); - $(this)[0].childNodes[i].nodeValue = change; - - } - }) - } - }, this); - }); - } - //e.firstChild.nodeValue = homeDict[e.firstChild.nodeValue]; - // 隐藏原dom元素避免与torntools发生冲突 - if ($(e).css('display') !== 'none') - $(e).css('display', 'none').after(`
` + homeDict[e.firstChild.nodeValue] + `
`); - }); - // 各表格左边的键 - $('span.divider span').each((i, e) => { - if (homeDict[$(e).text()]) - $(e).text(homeDict[$(e).text()]); - }); - return; - } - - // city - if (href.includes('city.php')) { - const cityOB = new MutationObserver(cityOBInit); - - function cityOBInit() { - cityOB.disconnect(); - cityTrans(); - cityOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); - } - - function cityTrans() { - titleTrans(); - contentTitleLinksTrans(); - - // Map or Quick Links - $('a.ui-tabs-anchor span').each((i, e) => { - if (cityDict[$(e).text()]) - $(e).text(cityDict[$(e).text()]); - }); - - // 标志建筑 标题 - if (cityDict[$('div.title-black').text()]) - $('div.title-black').text(cityDict[$('div.title-black').text()]); - - // 标志建筑 6个分类 - $('ul.map-symbols span').each((i, e) => { - if (cityDict[$(e).text()]) - $(e).text(cityDict[$(e).text()]); - }); - - // 地图显示模式 - // 不完全显示 文字 - $('span.inactive-mode').html(cityDict['inactive-mode1'] + `
` + cityDict['inactive-mode2']); - // 完全显示 文字 - $('span.active-mode').text(cityDict['active-mode']); - // 开关 - $('div.on-label').text('已开启'); - $('div.off-label').text('已关闭'); - - // 快速链接中的分类标题 - $('li.title').each((i, e) => { - if (cityDict[$(e).text()]) - $(e).text(cityDict[$(e).text()]); - }); - - // 快速链接中的区域 - $('li a[class^="font-num-"] span').each((i, e) => { - // log($(e).prev().attr('class')==='cql-gym') - if (cityDict[$(e).text()]) { - $(e).text(cityDict[$(e).text()]); - } else if ($(e).prev().attr('class') === 'cql-your-property') { - if (propertyDict[$(e).text().trim().slice(5)]) { - $(e).text('你的' + propertyDict[$(e).text().trim().slice(5)]); - } - } else if ($(e).prev().attr('class') === 'cql-gym') { - if (gymList[$(e).text().trim()]) { - $(e).text(gymList[$(e).text()]); - } else if (gymList[$(e).text().trim().split(' ').slice(0, 2).join(' ')]) { - $(e).text(gymList[$(e).text().trim().split(' ').slice(0, 2).join(' ')]); - } - } - }); - - // 快速链接中的分类选择 - $('div.sort-by label.marker-css').each((i, e) => { - if (cityDict[$(e).text()]) - $(e).text(cityDict[$(e).text()]); - }); - - // 快速链接中的sort by - $('span#wai-sort-by').each((i, e) => { - if (cityDict[$(e).text()]) - $(e).text(cityDict[$(e).text()]); - }); - } - - cityTrans(); - cityOB.observe(document.querySelector('div.content-wrapper'), {childList: true, subtree: true}); - return; - } - - // gym健身房页面 - if (href.includes('gym.php')) { - const gymOB = new MutationObserver(gymOBInit); - - function gymOBInit() { - gymOB.disconnect(); - gymTrans(); - gymOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); - } - - function gymTrans() { - titleTrans(); - contentTitleLinksTrans(); - const gymName = $('div[class^="notificationText"] b').text(); - - // 顶部提示信息 - $('div[class^="notificationText"] p').contents().each((i, e) => { - if (e.nodeName === 'B' && gymList[$(e).text().trim()]) { - $(e).text(gymList[$(e).text().trim()]); - return; - } - if (e.childNodes.length === 0 && gymDict[e.nodeValue.trim()]) - e.nodeValue = gymDict[e.nodeValue.trim()]; - }); - // 4属性标题 - $('h3[class^="title"]').each((i, e) => { - if (gymDict[$(e).text().trim()]) - $(e).text(gymDict[$(e).text().trim()]); - }); - // 4属性的介绍 与冰蛙冲突 - $('div[class^="description"] p:nth-child(1)').each((i, e) => { - if (gymDict[$(e).text().trim()]) - $(e).text(gymDict[$(e).text().trim()]); - }); - // 每次锻炼的花销 - $('div[class^="description"] p:nth-child(2)').each((i, e) => { - if (e.childNodes.length === 1) { - if (gymDict[$(e).text().trim()]) - $(e).text(gymDict[$(e).text().trim()]); - } else if (e.childNodes.length === 2) { - if (gymDict[e.lastChild.nodeValue.trim()]) { - e.lastChild.nodeValue = gymDict[e.lastChild.nodeValue.trim()]; - } - } - }); - // 锻炼页面所有按钮 - $('button[class^="button"]').each((i, e) => { - if (gymDict[$(e).text().trim()]) - $(e).text(gymDict[$(e).text().trim()]); - }); - // cancel按钮 - $('button[class^="cancel"]').each((i, e) => { - if (gymDict[$(e).text().trim()]) - $(e).text(gymDict[$(e).text().trim()]); - }); - // 锻炼的提示信息 - $('div[class^="messageWrapper"] p').each((i, e) => { - /** - * todo - *

You dug deep and completed 15 minutes of incline sprints

- * - */ - if (gymDict[$(e).text()]) - $(e).text(gymDict[$(e).text()]); - }); - // 健身房信息 标题 - $('div[class^="gymTitle"] h3').each((i, e) => { - if (gymDict[$(e).text()]) - $(e).text(gymDict[$(e).text()]); - else if (gymList[$(e).text().trim()]) - $(e).text(gymList[$(e).text().trim()]); - }); - // 健身房信息 属性名 - $('ul[class^="gymInfo"] b').each((i, e) => { - if (gymDict[$(e).text().trim()]) - $(e).text(gymDict[$(e).text().trim()]); - }); - - // 健身房状态信息 - // $('div[class^="gymStats"] b').each((i, e) => { - // log(e) - // if (gymDict[$(e).text().trim()]) - // $(e).text(gymDict[$(e).text().trim()]); - // }); - // - // // 健身房状态值 - // $('div[class^="gymStats"] span[class^=value]').each((i, e) => { - // if ($(e).text().indexOf("per train") > 0) - // $(e).text($(e).text().split(" ")[0] + gymDict["per train"]); - // else if (gymDict[$(e).text().trim()]) - // $(e).text(gymDict[$(e).text().trim()]); - // }); - - // 健身房信息 属性值 - $('ul[class^="gymInfo"] span[class^="value"]').each((i, e) => { - if (gymDict[$(e).text().trim()]) - $(e).text(gymDict[$(e).text().trim()]); - }); - // 健身房信息 具体锻炼项目 - $('span[class^="exerciseName"]').each((i, e) => { - if (gymDict[$(e).text().trim()]) - $(e).text(gymDict[$(e).text().trim()]); - }); - // 购买提示信息 - $('div[class^="confirmMessage"] p[role="alert"]').each((i, e) => { - if (gymDict[$(e).text().trim()]) - $(e).text(gymDict[$(e).text().trim()]); - }); - } - - gymTrans(); - gymOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); - return; - } - - // 物品页面 - if (href.contains(/item\.php/)) { - if (href.includes('item.php?temp=')) return; - // 标题和右边的链接 - initOB(document.querySelector('.content-title'), {childList: true}, - () => { - titleTrans(); - contentTitleLinksTrans(); - }); - // 套装预览中间的文字 - const $loadouts_root = document.getElementById('loadoutsRoot'); - if ($loadouts_root) { - initOB($loadouts_root, {subtree: true, attributes: true}, () => { - const el = $loadouts_root.querySelector('div[class^="type___"]'); - if (el && itemPageDict[el.innerText.trim()]) { - el.innerText = itemPageDict[el.innerText.trim()]; - } - }); - } - // 手机选项按钮 物品名 物品详情 - const options = { - attributes: true, - subtree: true, - attributeFilter: ["aria-hidden",] - }; - const translated = {cat: '', count: -1}; - const translatedOnce = {item_opt: -1, opt_icon_count: -1}; - initOB(document.getElementById('category-wrap'), options, () => { - // 手机操作选项 - const $item_opt = document.querySelectorAll(`ul.itemsList span.opt-name`); - if (translatedOnce.item_opt !== $item_opt.length - 1) { - let count = -1; - $item_opt.forEach((e, i) => { - if (itemPageDict[e.firstChild.nodeValue.trim()]) { - e.firstChild.nodeValue = itemPageDict[e.firstChild.nodeValue.trim()]; - } - count = i; - }); - translatedOnce.item_opt = count !== -1 ? count : -1; - } - // 物品名 - const $active_tab = document.querySelector('ul.itemsList[aria-expanded="true"]'); - if (!$active_tab) return; - const $active_item_list = $active_tab.querySelectorAll('span.name'); - const itemCat = $active_tab.id; - if ($active_item_list.length - 1 !== translated.count || itemCat !== translated.cat) { - let count = -1; - // 物品名 - $active_item_list.forEach((e, i) => { - if (!e.classList.contains('wh-translated')) { - if (itemNameDict[e.innerText.trim()]) { - e.classList.add('wh-translated'); - const trans_dom = document.createElement('span'); - trans_dom.classList.add('wh-translate'); - trans_dom.setAttribute('style', 'margin: 0 0 0 1em'); - trans_dom.append(itemNameDict[e.innerText.trim()]); - e.after(trans_dom); - // .after(`${itemNameDict[$(e).text().trim()]}`); - } - } - count = i; - }); - - if (count !== -1) { - translated.cat = itemCat; - translated.count = count; - } - } - // 物品详情 - const $show_item_info = $active_tab.querySelector('li.show-item-info'); - showItemInfoTrans($show_item_info); - // 物品右操作按钮 - const $opt_icon_tooltip = $('ul.actions-wrap span.icon-h'); - if (translatedOnce.opt_icon_count !== $opt_icon_tooltip.length - 1) { - let count = -1 - $opt_icon_tooltip.each((i, e) => { - if (itemPageDict[e.attributes.title.nodeValue]) { - e.attributes.title.nodeValue = itemPageDict[e.attributes.title.nodeValue]; - } - count = i; - }); - if (count !== -1) { - translatedOnce.opt_icon_count = count; - } - } - }); - // 黑框 - const $title_black = document.querySelector('div.title-black'); - if ($title_black) { - const $your_items = $title_black.querySelector('span.m-hide'); - if (itemPageDict[$your_items.innerText.trim()]) { - $your_items.innerText = itemPageDict[$your_items.innerText.trim()]; - } - // 黑框分类标题 - const $items_type_name = $title_black.querySelector('span.items-name'); - initOB($items_type_name, {childList: true}, () => { - if (itemPageDict[$items_type_name.innerText.trim()]) { - $items_type_name.innerText = itemPageDict[$items_type_name.innerText.trim()]; - } - }); - } - // 分类浮动文字 - const $data_type = document.querySelectorAll('li#categoriesItem a'); - $data_type.forEach((e) => { - if (itemPageDict[e.getAttribute('title')]) { - e.setAttribute('title', itemPageDict[e.attributes.title.nodeValue]); - } - }); - return; - } - - // npc商店 - if (href.contains(/(shops|bigalgunshop)\.php/)) { - // 标题和右边的链接 - const $cont_title = document.querySelector('.content-title'); - initOB($cont_title, {childList: true, subtree: true}, () => { - titleTrans(); - contentTitleLinksTrans(); - }); - const $wrapper = document.querySelector('.content-wrapper'); - // [购买部分] - const $buy_items_wrapper = $wrapper.querySelector('.buy-items-wrap'); - if ($buy_items_wrapper) { - // 黑框标题 - const $buy_black_title = $buy_items_wrapper.querySelector('.title-black'); - if ($buy_black_title && npcShopDict[$buy_black_title.firstChild.nodeValue.trim()]) { - $buy_black_title.firstChild.nodeValue = npcShopDict[$buy_black_title.firstChild.nodeValue.trim()]; - } - // 各个物品 - const $items = $buy_items_wrapper.querySelectorAll('ul.items-list > li.torn-divider'); - $items.forEach(e => { - // 物品名 - const $item_name = e.querySelector('span.desc span.name.bold'); - if ($item_name && itemNameDict[$item_name.innerText.trim()]) { - $item_name.innerText = `${itemNameDict[$item_name.innerText.trim()]}(${$item_name.innerText.trim()})`; - } - // 类型和存货 - const $item_stock = e.querySelector('span.desc span.stock'); - if ($item_stock) $item_stock.childNodes.forEach(e => { - if (e.nodeType === 1) { - if (npcShopDict[e.innerText.trim()]) e.innerText = npcShopDict[e.innerText.trim()]; - } else { - if (npcShopDict[e.nodeValue.trim()]) e.nodeValue = npcShopDict[e.nodeValue.trim()]; - } - }); - // buy按钮 - const $buy_btn = e.querySelector('button.wai-support'); - if ($buy_btn && npcShopDict[$buy_btn.childNodes[0].nodeValue.trim()]) { - $buy_btn.childNodes[0].nodeValue = npcShopDict[$buy_btn.childNodes[0].nodeValue.trim()]; - } - // 买前确认 - const $confirm = e.querySelector('span.confirm'); - const $confirm_msg = $confirm.querySelector('span'); - if ($confirm_msg && npcShopDict[$confirm_msg.innerText.trim()]) { - $confirm_msg.innerText = npcShopDict[$confirm_msg.innerText.trim()]; - } - const $amount_item_name = $confirm.querySelector('span.count').nextSibling; - if ($amount_item_name && !$amount_item_name.nodeValue.contains(CC_set)) { - const item_name = $amount_item_name.nodeValue.trim().split(' ').slice(1, -1).join(' '); - const item_name_trans = itemNameDict[item_name] || item_name; - $amount_item_name.nodeValue = `个[${item_name_trans}],总计$`; - } - const $confirm_a = $confirm.querySelectorAll('span.confirm-act a'); - $confirm_a.forEach(e => { - if (npcShopDict[e.innerText.trim()]) e.innerText = npcShopDict[e.innerText.trim()]; - }); - }); - // 展开的物品详情 - initOB($wrapper, {childList: true, subtree: true}, () => { - const $item_desc = $wrapper.querySelector('.show-item-info') || $wrapper.querySelector('.view-item-info'); - showItemInfoTrans($item_desc); - }); - } - // [卖出部分] - const $sell_items_wrapper = $wrapper.querySelector('.sell-items-wrap'); - if ($sell_items_wrapper) { - // 黑框标题 - const $title = $sell_items_wrapper.querySelectorAll('ul.title li'); - $title.forEach(el => { - el.childNodes.forEach(e => { - if (e.nodeType === 1) { - if (npcShopDict[e.innerText.trim()]) { - e.innerText = npcShopDict[e.innerText.trim()]; - return; - } - const spl = e.innerText.trim().split(' '); - if (spl.length > 3) { - const shop_name = spl[2] === 'the' ? spl.slice(3).join(' ') : spl.slice(2).join(' '); - const shop_name_trans = npcShopDict[shop_name] || titleDict[shop_name] || cityDict[shop_name] || null; - e.innerText = `物品给${shop_name_trans || shop_name}`; - } - } else { - if (npcShopDict[e.nodeValue.trim()]) e.nodeValue = npcShopDict[e.nodeValue.trim()]; - } - }); - }); - // 物品名 - const $items_name = $sell_items_wrapper.querySelectorAll('span.name'); - $items_name.forEach(el => { - if (itemNameDict[el.innerText.trim()]) el.innerText += - ` ${itemNameDict[el.innerText.trim()]}`; - }); - // 按钮 - const $btn = $sell_items_wrapper.querySelectorAll('button'); - $btn.forEach(e => { - if (npcShopDict[e.innerText.trim()]) e.innerText = npcShopDict[e.innerText.trim()]; - }); - // select btn - const $select_btn = $sell_items_wrapper.querySelector('li.select button.wai-btn'); - if ($select_btn) { - initOB($select_btn, {childList: true}, () => { - if ($select_btn && npcShopDict[$select_btn.innerText.trim()]) { - $select_btn.innerText = npcShopDict[$select_btn.innerText.trim()]; - } - }); - } - // 取消按钮 - const $cancel = $sell_items_wrapper.querySelector('span.cancel a'); - if ($cancel && npcShopDict[$cancel.innerText.trim()]) { - $cancel.innerText = npcShopDict[$cancel.innerText.trim()]; - } - // 卖出确认文字 - const $sell_confirm = $sell_items_wrapper.querySelector('div.sell-confirm'); - if ($sell_confirm) { - const $msg = $sell_confirm.childNodes[0]; - if (npcShopDict[$msg.nodeValue.trim()]) $msg.nodeValue = npcShopDict[$msg.nodeValue.trim()]; - const $total_value = $sell_confirm.querySelector('span.profit').childNodes[0]; - if (npcShopDict[$total_value.nodeValue.trim()]) $total_value.nodeValue = npcShopDict[$total_value.nodeValue.trim()]; - } - } - // [出售PT部分] - const $sell_pt_wrapper = $wrapper.querySelector('.sell-points-wrap'); - if ($sell_pt_wrapper) { - // 黑框 - const $title_black = $sell_pt_wrapper.querySelector('.title-black'); - if (npcShopDict[$title_black.innerText.trim()]) { - $title_black.innerText = npcShopDict[$title_black.innerText.trim()]; - } - } - return; - } - - // 股票 - if (href.contains(/page\.php\?sid=stocks/)) { - const stockOB = new MutationObserver(() => { - stockOB.disconnect(); - titleTrans(); - contentTitleLinksTrans(); - stockTrans(); - stockOB.observe($('.content-wrapper').get(0), { - characterData: true, - attributes: true, - subtree: true, - childList: true - }); - }); - const stockTrans = function stockTrans() { - // 表头 - $('ul.title-black').find('*').contents().each((i, e) => { - if (e.nodeType === 3 && stockDict[e.nodeValue.trim()]) { - e.nodeValue = stockDict[e.nodeValue.trim()]; - } - }); - // 名称 - $('div[class^="nameContainer"]').each((i, e) => { - if (e.childNodes[0].nodeValue && stockDict[e.childNodes[0].nodeValue.trim()]) { - e.childNodes[0].nodeValue = stockDict[e.childNodes[0].nodeValue.trim()]; - } - }); - // 右侧bb名 - $('div[class^="dividendInfo"] p').each((i, e) => { - const spl = $(e).text().trim().split(' '); - if (stockDict[$(e).text().trim()]) { - $(e).text(stockDict[$(e).text().trim()]); - } else if (/[0-9]x$/.test(spl[0])) { - const itemName = spl.slice(1).join(' '); - const num = spl[0].slice(0, -1); - $(e).text(`${num}个${itemNameDict[itemName] ? itemNameDict[itemName] : itemName}`); - } - }); - // 股价详情 - $('#panel-priceTab ul[role="tablist"] label span:last-child').each((i, e) => { - if (stockDict[$(e).text()]) { - $(e).text(stockDict[$(e).text()]); - } - }); - $('ul[class^="priceInfoList___"] li').contents().each((i, e) => { - if (e.nodeType === 3) { - if (stockDict[e.nodeValue.trim()]) { - e.nodeValue = stockDict[e.nodeValue.trim()]; - } - } - }); - // 点开购买后 - $('div#panel-ownedTab div[class^="manageBlock"] *').contents().each((i, e) => { - if (e.nodeType === 1) { - if (stockDict[$(e).text().trim()]) { - $(e).text(stockDict[$(e).text().trim()]); - } - } else if (e.nodeType === 3) { - if (stockDict[e.nodeValue.trim()]) e.nodeValue = stockDict[e.nodeValue.trim()]; - else if (/\$[0-9]+ after the 0\.1% fee of \$[0-9]+$/.test(e.nodeValue.trim())) { - e.nodeValue = e.nodeValue.trim() - .replace('after the', stockDict['after the']) - .replace('fee of', stockDict['fee of']); - } - } - }); - // 点开购买后的历史栏 - $('div#panel-ownedTab div[class^="transactionsContainer"] li').each((i, e) => { - e = e.childElementCount === 0 ? e : e.children[0]; - if (stockDict[$(e).text().trim()]) { - $(e).text(stockDict[$(e).text().trim()]); - } - }); - // 历史购买show more - const $show_more = document.querySelector('li[class^="showMore___"] button'); - if ($show_more && $show_more.innerText.trim().contains(/^Show [0-9]+ more$/)) { - const number = $show_more.innerText.trim().split(' ')[1]; - $show_more.innerText = `显示另外${number}条`; - } - // 点开bb后 - $('div#panel-dividendTab div[class^="message"] *').contents().each((i, e) => { - if (e.nodeType !== 3) return; - if (!e.nodeValue.trim()) return; - if (stockDict[e.nodeValue.trim()]) { - e.nodeValue = stockDict[e.nodeValue.trim()]; - } - // 第n个increment 1st 2nd 3rd 4th - else if (/[0-9][snrt][tdh]$/.test(e.nodeValue.trim())) { - e.nodeValue = `第${e.nodeValue.trim().slice(0, -2)}个`; - } - // 物品 - else if (/[0-9]x$/.test(e.nodeValue.trim().split(' ')[0])) { - const spl = e.nodeValue.trim().split(' '); - const itemName = spl.slice(1).join(' '); - e.nodeValue = - ` ${spl[0].replace('x', '个') - } ${itemNameDict[itemName] ? itemNameDict[itemName] : itemName - }`; - } else { - if (/[\u4e00-\u9fa5]/.test(e.nodeValue)) return; - if (/\b\$?[0-9,]+$/.test(e.nodeValue)) return; - log(`未找到翻译:[${e.nodeValue.trim()}]`); - } - }); - }; - stockTrans(); - stockOB.observe($('.content-wrapper').get(0), { - characterData: true, - attributes: true, - subtree: true, - childList: true - }); - return; - } - - // 教育页面 - if (href.indexOf('education.php') >= 0) { - const eduOB = new MutationObserver(eduOBInit); - - function eduOBInit() { - eduOB.disconnect(); - eduTrans(); - eduOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); - } - - function eduTrans() { - titleTrans(); - contentTitleLinksTrans(); - - // 大科目、学院标题 - $('div.content-wrapper div.title').each((i, e) => { - if (eduDict[$(e).text().trim()]) - e.firstChild.nodeValue = eduDict[$(e).text().trim()]; - }); - // 教育主页提示内容 和 学院详情 小课程提示信息 - $('div.content-wrapper div[class^="msg"]').find('*').contents().each((i, e) => { - if (e.nodeValue === null) return; - if (eduDict[e.nodeValue.trim()]) { - e.nodeValue = eduDict[e.nodeValue.trim()]; - } else if (e.nodeValue.indexOf('second') >= 0 || - e.nodeValue.indexOf('minute') >= 0 || - e.nodeValue.indexOf('hour') >= 0 || - e.nodeValue.indexOf('day') >= 0) { - e.nodeValue = e.nodeValue - .replace('days', '天') - .replace('day', '天') - .replace('hours', '时') - .replace('hour', '时') - .replace('minutes', '分') - .replace('minute', '分') - .replace('and', '和') - .replace('seconds', '秒') - .replace('second', '秒'); - } - }); - // 学院详情标题 - $('div.content-wrapper div.title-black').each((i, e) => { - if (e.childNodes.length === 3) - if (eduDict[e.lastChild.nodeValue.trim()]) - e.lastChild.nodeValue = ' ' + eduDict[e.lastChild.nodeValue.trim()]; - if (eduDict[$(e).text().trim()]) - $(e).text(eduDict[$(e).text().trim()]); - }); - // 学院详情 小课程标题 - $('div.content-wrapper span.module-name').each((i, e) => { - if (eduDict[$(e).text().trim()]) - $(e).text(eduDict[$(e).text().trim()]); - }); - // 学院详情 课程的描述 - $('div.content-wrapper p.desc').each((i, e) => { - if (eduDict[$(e).text().trim()]) - $(e).text(eduDict[$(e).text().trim()]); - }); - // 课程详情 7 标题 - $('div.module-desc p.title').each((i, e) => { - if (eduDict[$(e).text().trim()]) - $(e).text(eduDict[$(e).text().trim()]); - }); - // 课程介绍中的所有li元素 - $('div.module-desc ul.info').find('*').contents().each((i, e) => { - if (e.nodeValue === null) return; - if (eduDict[e.nodeValue.trim()]) - e.nodeValue = eduDict[e.nodeValue.trim()]; - else if (e.nodeValue.indexOf('Length') >= 0) { - e.nodeValue = e.nodeValue.replace('Length', eduDict['Length']) - .replace('d ', '日') - .replace('h ', '时') - .replace('m ', '分'); - } else if (e.nodeValue.indexOf('Cost') >= 0) { - e.nodeValue = e.nodeValue.replace('Cost', eduDict['Cost']); - } else if (e.nodeValue.indexOf('manual labor') >= 0) { - e.nodeValue = e.nodeValue.replace('manual labor', eduDict['manual labor']) - .replace('Gain', eduDict['Gain']) - .replace('upon completion', eduDict['upon completion']); - } else if (e.nodeValue.indexOf('endurance') >= 0) { - e.nodeValue = e.nodeValue.replace('endurance', eduDict['endurance']) - .replace('Gain', '获得') - .replace('upon completion', eduDict['upon completion']); - } else if (e.nodeValue.indexOf('intelligence') >= 0) { - e.nodeValue = e.nodeValue.replace('intelligence', eduDict['intelligence']) - .replace('Gain', '获得') - .replace('upon completion', eduDict['upon completion']); - } - }); - } - - eduTrans(); - eduOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); - return; - } - - // profile 玩家资料页面 - if (href.contains(/profiles\.php\?XID=\d+/)) { - const $wrapper = document.querySelector('.content-wrapper'); - const profileOB = new MutationObserver(() => { - profileOB.disconnect(); - titleTrans(); - contentTitleLinksTrans(); - profileTrans(); - profileOB.observe($wrapper, { - characterData: true, - attributes: true, - subtree: true, - childList: true - }); - }); - const profileTrans = function profileTrans() { - const playerName = document.title.trim().contains(/('s |s' )/) - ? document.title.trim().split(/('s |s' )/)[0] - : null; - if (!playerName) { - console.error('翻译助手错误:获取用户名失败。'); - try { - profileOB.disconnect() - } catch { - } - return; - } - - // 黑框标题 - $('.content-wrapper .title-black').each((i, e) => { - if (i === 1) { - if (profileDict[e.firstChild.nodeValue.trim().replace(playerName, '{$}')]) { - e.firstChild.nodeValue = ( - profileDict[$(e).text().trim().replace(playerName, '{$}')] - .replace('{$}', playerName) - ); - } - return; - } - if (profileDict[$(e).text().trim()]) { - $(e).text(profileDict[$(e).text().trim()]); - } - }); - // level rank age - $('.profile-information-wrapper .box-info .box-name').each((i, e) => { - if (profileDict[e.innerText.trim()]) e.innerText = profileDict[e.innerText.trim()]; - }); - // todo player title - // todo player rank title - // 行动框的描述 - const action_desc = $('#profile-container-description.profile-container-description'); - if (profileDict[action_desc.text().trim()]) { - action_desc.html(`${profileDict[action_desc.text().trim()]}`); - } else if (profileDict[action_desc.text().trim().replace(playerName, '{$}')]) { - action_desc.html( - `${profileDict[action_desc.text().trim().replace(playerName, '{$}')] - .replace('{$}', playerName)}` - ); - } else if (action_desc.text().contains(/is on your (friend|enemy) list/)) { - const spl = action_desc.text().trim().split(' '); - const mark = spl.length === 6 - ? null - : spl.slice(7).join(' '); - switch (spl[4]) { - case 'friend': - if (profileDict['{$} is on your friend list']) { - action_desc.html( - `${profileDict['{$} is on your friend list'] - .replace('{$}', playerName) - }${mark ? ' : ' + mark : '' - }` - ); - } - break; - case 'enemy': - if (profileDict['{$} is on your enemy list']) { - action_desc.html( - `${profileDict['{$} is on your enemy list'] - .replace('{$}', playerName) - }${mark ? ' : ' + mark : '' - }` - ); - } - break; - } - } else { - if ($('.wh-translated').length <= 0) { - log(`未找到翻译: “${action_desc.text().trim()}”`); - } - } - // 添加敌人或朋友的界面 - $('.add-user .reason-wrapper').find('*').contents().each((i, e) => { - if (e.nodeType === 3) { - if (profileDict[e.nodeValue.trim()]) { - e.nodeValue = profileDict[e.nodeValue.trim()]; - } else if (/\b[1-4]?[0-9]\b/.test(e.nodeValue.trim().slice(0, 2))) { - const left = e.nodeValue.trim().slice(0, 2); - if (profileDict['{$} characters left']) { - e.nodeValue = profileDict['{$} characters left'].replace('{$}', left); - } - } - } - }); - // 状态 - playerStatusTrans($('.profile-status .profile-container span')); - // 表格 - $('ul.info-table li div').each((i, e) => { - const $e = $(e); - // 左 - if ($e.attr('class').contains(/user-information-section/)) { - const elem = e.children[0]; - const $elem = $(elem); - if (profileDict[$elem.text().trim()]) $elem.text(profileDict[$elem.text().trim()]); - } - // 右 值 - else { - if (profileDict[$e.text().trim()]) { - $e.children().text(profileDict[$e.text().trim()]); - return; - } - switch (i) { - case 5: // 帮派 - case 7: { // 公司 - if ($e.text().contains(CC_set)) return; - const $span = e.children[0].children[0]; - const pos = $span.firstChild.nodeValue.trim().split(' ').slice(0, -1).join(' '); - $span.firstChild.nodeValue = ''; - $($span).append(` 的 ${pos}`); - return; - } - case 11: { - // 住宅 - $e.find('span *').contents().each((i, el) => { - if (el.nodeType === 3) { - if (profileDict[el.nodeValue.trim()]) { - el.nodeValue = profileDict[el.nodeValue.trim()] - } else if (propertyDict[el.nodeValue.trim()]) { - el.nodeValue = propertyDict[el.nodeValue.trim()] - } - } - }); - return; - } - case 13: { - // 结婚状态 - if ($e.text().contains(CC_set)) return; - const days = $e.text().contains(/ [0-9]+ /) - ? $e.text().trim().split(' ')[4] - : null; - if (days) { - e.children[0].children[0].childNodes[0].nodeValue = '与 '; - e.children[0].children[0].childNodes[2].nodeValue = ` 结婚${days}天`; - } else { - $e.find('span *').contents().each((i, el) => { - if (el.nodeType === 3) { - if (profileDict[el.nodeValue.trim()]) { - el.nodeValue = profileDict[el.nodeValue.trim()] - } - } - }); - } - return; - } - case 23: { - // 39 minutes ago - if ($e.text().contains(/ago/)) { - $e.children().text($e.text() - .replace('ago', '前') - .replace('and', '') - .replace('seconds', '秒') - .replace('second', '秒') - .replace('minutes', '分') - .replace('minute', '分') - .replace('hours', '时') - .replace('hour', '时') - .replace('days', '日') - .replace('day', '日') - .replaceAll(' ', '') - ); - } - return; - } - } - /** - 1 'Woohoo [2687093]' - 3 'Civilian' - 5 'Knight of Silver Hand' - 7 'Director of -- FaFaFa --' - 9 '1567 / 1567' - 11 'Private Island (With Spouse)' - 13 'Married to Sabrina_Devil for 42 days' - 15 '153' - 17 '4' - 19 '4\n  好人\n  坏比指数: 1\n ' - 21 '2 (0 karma)' - 23 '52 minutes ago' - */ - } - }); - // doesnt wish to share - const $nShare = $('.personal-info p'); - $nShare.contents().each((i, e) => { - if (e.nodeType === 3) { - if (profileDict[e.nodeValue.trim()]) e.nodeValue = profileDict[e.nodeValue.trim()]; - } - }); - // 活动状态 - const $cmpSt = $('.profile-container.competition-wrap span') - $cmpSt.text(profileDict[$cmpSt.text().trim()] || $cmpSt.text()); - - sendCashTrans('.content-wrapper'); - }; - profileTrans(); - profileOB.observe($wrapper, { - characterData: true, - attributes: true, - subtree: true, - childList: true - }); - return; - } - - // 报纸 - if (href.contains(/(newspaper|joblist|freebies|newspaper_class|personals|bounties|comics)\.php/)) { - const newspaperOB = new MutationObserver(() => { - newspaperOB.disconnect(); - newspaperTrans(); - newspaperOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); - }); - - function newspaperTrans() { - titleTrans(); - contentTitleLinksTrans(); - if ($('a.newspaper-link').length === 0) return; - // 导航菜单 - $('a.newspaper-link').contents().each((i, e) => { - if (newspaperDict[e.nodeValue]) - e.nodeValue = newspaperDict[e.nodeValue]; - }); - // 公众号广告 - $('div.price.left').contents()[2].nodeValue = '文章翻译请关注中文公众号Torncity'; - // 日期翻译 - const $date_label = document.querySelector('span.date-label'); - const date_reg = /^[FMSTW][adehinorstuy]+, [ADFJMNOS][abceglnoprtuvy]+ [1-3]?[0-9], 20[0-9][0-9]$/; - if ($date_label && $date_label.innerText.trim().contains(date_reg)) { - const date_format = $date_label.innerText.trim().replaceAll(',', ''); - const date_spl = date_format.split(' '); - const date = {w: date_spl[0], m: date_spl[1], d: date_spl[2], y: date_spl[3]}; - const month_trans = { - 'Jan': 1, - 'Feb': 2, - 'Mar': 3, - 'Apr': 4, - 'May': 5, - 'Jun': 6, - 'Jul': 7, - 'Aug': 8, - 'Sep': 9, - 'Oct': 10, - 'Nov': 11, - 'Dec': 12 - }; - $date_label.innerText = `${date.y}年${month_trans[date.m] || date.m}月${date.d}日`; - } - // 菜单下的信息 工作 壁纸 广告 悬赏 - $('div.help-message').find('*').contents().each((i, e) => { - if (!e.nodeValue || e.nodeValue.trim() === '') return; - if (newspaperDict[e.nodeValue.trim()]) - e.nodeValue = newspaperDict[e.nodeValue.trim()]; - else if (newspaperDict[e.nodeValue.trim().slice(0, 50)]) - e.nodeValue = newspaperDict[e.nodeValue.trim().slice(0, 50)]; - }); - // 右边栏 - $('div[class^="sideCont"] [class^="title"]').contents().each((i, e) => { - if (newspaperDict[e.nodeValue]) - e.nodeValue = newspaperDict[e.nodeValue]; - }); - // 彩票信息 - $('span[class^="winner"]').each((i, e) => { - }); - // 底部链接 - // Why not visit our sponsor? - if (newspaperDict[$('div.link-left').text().trim()]) - $('div.link-left').text(newspaperDict[$('div.link-left').text().trim()]); - // View all | Advertise here - $('div.link-right a').contents().each((i, e) => { - if (newspaperDict[e.nodeValue.trim()]) - e.nodeValue = newspaperDict[e.nodeValue.trim()]; - }) - $('.bounties-list-title li').each((i, e) => { - if (newspaperDict[$(e).text().trim()]) { - $(e).text(newspaperDict[$(e).text().trim()]); - } - }); - // 交友 - if (window.location.href.contains(/personals/)) { - $('div.personals-wrap span.msg').find('*').contents().each((i, e) => { - if (!e.nodeValue || e.nodeValue.trim() === '') return; - if (newspaperDict[e.nodeValue.trim()]) - e.nodeValue = newspaperDict[e.nodeValue.trim()]; - }); - } - // 漫画 - if (window.location.href.contains(/freebies/)) { - if (newspaperDict[$('div.bonus-wrap a').text().trim()]) - $('div.bonus-wrap a').text(newspaperDict[$('div.bonus-wrap a').text().trim()]); - } - // 悬赏 - if (window.location.href.contains(/bounties/)) { - // 列表前的总数 - const $total = $('.bounties-total'); - if ($total.text().contains(/A total of [0-9]+ listings were found/)) { - const num = $total.text().trim().split(' ')[3]; - if (newspaperDict['A total of {$} listings were found.']) { - $total.text(newspaperDict['A total of {$} listings were found.'] - .replace('{$}', num)); - } - } - // 列表 - $('.user-info-wrap div *').contents().each((i, e) => { - if (e.nodeType === 3) { - if (newspaperDict[e.nodeValue.trim()]) { - e.nodeValue = newspaperDict[e.nodeValue.trim()]; - } - } - }); - // claim - $('ul.bounties-list div.claim button').each((i, e) => { - if (newspaperDict[$(e).text().trim()]) { - $(e).text(newspaperDict[$(e).text().trim()]); - } - }); - $('ul.bounties-list div.claim a').each((i, e) => { - if (newspaperDict[$(e).text().trim()]) { - $(e).text(newspaperDict[$(e).text().trim()]); - } - }); - // 3选项框 - $('.add-bounties-wrap .name').contents().each((i, e) => { - if (e.nodeType === 3) { - if (newspaperDict[e.nodeValue.trim()]) { - e.nodeValue = newspaperDict[e.nodeValue.trim()]; - } - } else if (e.nodeType === 1) { - if (newspaperDict[$(e).text().trim()]) { - $(e).text(newspaperDict[$(e).text().trim()]); - } - } - }); - // 匿名选项 - const $anony = $('.choice-container label'); - if (newspaperDict[$anony.text().trim()]) { - $anony.text(newspaperDict[$anony.text().trim()]); - } - // 发钱按钮 - const $$symbol = $('span.input-money-symbol'); - if (sendCashDict[$$symbol.attr('title')]) { - $$symbol.attr('title', sendCashDict[$$symbol.attr('title')]) - } - // 10/10滑动 - const $slider_title = $('.slider-title'); - if ($slider_title.text().contains(/Quantity:/)) { - $slider_title.text($slider_title.text().replace('Quantity', '数量')); - } - // 价钱信息 - $('.confirm-bounties *').contents().each((i, e) => { - if (e.nodeType === 3) { - if (newspaperDict[e.nodeValue.trim()]) { - e.nodeValue = newspaperDict[e.nodeValue.trim()]; - } - } - }); - // 下单前确认对话 - $('.confirm-buttons *').contents().each((i, e) => { - if (e.nodeType === 3) { - if (newspaperDict[e.nodeValue.trim()]) { - e.nodeValue = newspaperDict[e.nodeValue.trim()]; - return; - } - switch (i) { - case 7: - case 10: { - if (e.nodeValue.contains(/[0-9] bounties/)) { - e.nodeValue = e.nodeValue.replace('bounties', '次') - } else if (e.nodeValue.contains(/with the reason: .+\?/)) { - e.nodeValue = e.nodeValue.replace('with the reason', '吗,悬赏原因') - } - break; - } - } - } - }); - // place - const $place = $('.place-buttons input'); - if (newspaperDict[$place.attr('value')]) { - $place.attr('value', newspaperDict[$place.attr('value')]); - } - // cancel - const $cancel = $('.place-buttons a.cancel'); - if (newspaperDict[$cancel.text().trim()]) { - $cancel.text(newspaperDict[$cancel.text().trim()]); - } - } - } - - newspaperTrans(); - newspaperOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); - return; - } - - // npc买房 estateagents - if (href.includes('estateagents.php')) { - titleTrans(); - contentTitleLinksTrans(); - $('div.estate-info div.title').each((i, e) => { - if (propertyDict[e.firstChild.nodeValue]) - e.firstChild.nodeValue = propertyDict[e.firstChild.nodeValue]; - }); - - return; - } - - // properties房屋页面 - if (href.includes('properties.php')) { - const isRent = window.location.href.indexOf('rent') >= 0; - // const isRentOrSell = isRent || window.location.href.indexOf('sell') >= 0; - // const isOption = window.location.href.indexOf('p=options') >= 0; - // const isExtension = window.location.href.indexOf('step=viewOfferExtension') >= 0; - const propertyOB = new MutationObserver(() => { - propertyOB.disconnect(); - titleTrans(); - contentTitleLinksTrans(); - propertyTrans(); - propertyOB.observe($('div.content-wrapper').get(0), {childList: true, subtree: true}); - }); - const propertyTrans = function propertyTrans() { - // 从玩家处租或买 - if (isRent || window.location.href.indexOf('sell') >= 0) { - // 黑框标题 - $('div.title-black span').each((i, e) => { - e.firstChild.nodeValue = '您想查看哪些房产?'; - }); - // 房屋汉化 - $('ul.info-cont label.marker-css').contents().each((i, e) => { - if (propertyDict[e.nodeValue]) - e.nodeValue = propertyDict[e.nodeValue]; - }); - //搜索按钮 - $('div.btn-search button').text('搜索'); - $('div.search-text a').text('搜索'); - // 表头信息 - $('div.users-list-title div').each((i, e) => { - if (propertyDict[$(e).text()]) - $(e).text(propertyDict[$(e).text()]); - }); - // 确认购买提示 - $('div[class="confirm-text"] span.question').each((i, e) => { - const propName = e.firstElementChild.innerText.trim().split(' ').slice(8).join(' '); - - const hasAnother = $(e).text().indexOf('another') > 0; - if (hasAnother) { - e.firstElementChild.firstChild.nodeValue = '你确定要'; - e.firstElementChild.firstChild.nodeValue += isRent ? '租用' : '购买'; - e.firstElementChild.childNodes[1].firstChild.nodeValue = '另一个'; - e.firstElementChild.childNodes[2].nodeValue = propertyDict[propName]; - } else { - e.firstElementChild.firstChild.nodeValue = '你确定要'; - e.firstElementChild.firstChild.nodeValue += isRent ? '租用' : '购买'; - e.firstElementChild.firstChild.nodeValue += propertyDict[propName]; - } - e.children[1].firstChild.nodeValue = '花费 '; - e.children[1].childNodes[2].nodeValue = isRent ? ' 租期 ' : '?'; - if (isRent) - e.children[1].childNodes[4].nodeValue = ' 天?'; - }); - - // 房屋详情表格 - $('div.info-block span.bold').each((i, e) => { - if (e.childElementCount === 2) { - /** - * - On - "Market" - Price - ":" - - */ - e.firstElementChild.firstChild.nodeValue = ''; - e.childNodes[2].nodeValue = '市场价'; - e.childNodes[3].firstChild.nodeValue = ''; - e.childNodes[4].nodeValue = ':'; - } else { - if (propertyDict[e.firstChild.nodeValue.trim()]) - e.firstChild.nodeValue = propertyDict[e.firstChild.nodeValue.trim()]; - } - }); - $('div.rental-period span.bold').each((i, e) => { - if (propertyDict[e.firstChild.nodeValue.trim()]) - e.firstChild.nodeValue = propertyDict[e.firstChild.nodeValue.trim()]; - }); - // 窄边 cost happy - $('span.title-laptop.bold').each((i, e) => { - if (propertyDict[$(e).text().trim()]) - $(e).text(propertyDict[$(e).text().trim()]); - }); - // modification - $('div.title.bold.left').each((i, e) => { - if (propertyDict[e.firstChild.nodeValue]) - e.firstChild.nodeValue = propertyDict[e.firstChild.nodeValue]; - }); - - return; - } - // 房屋选项 - if (window.location.href.indexOf('p=options') >= 0) { - // 页面的黑框标题 - $('div.content-wrapper div.title-black').each((i, e) => { - if (propertyDict[$(e).text().trim()]) - $(e).text(propertyDict[$(e).text().trim()]); - }); - // 所有li内容 - // $('div.content-wrapper div.customize-opt li').find('*') - // .contents().each((i,e)=>{ - // if(e.nodeType!==3)return;log(e) - // }); - return; - } - // 房屋详情 - if (window.location.href.indexOf('p=propertyinfo') >= 0) { - return; - } - // 延期、合同 - if (window.location.href.indexOf('step=viewOfferExtension') >= 0) { - return; - } - // 自己的所有房产 页面 - { - // 顶部3标题 - $('ul.property-tabs a.ui-tabs-anchor div').contents().each((i, e) => { - if (propertyDict[e.nodeValue]) { - e.nodeValue = propertyDict[e.nodeValue]; - } - }); - // 图片下的描述部分 - $('ul.properties-list div.image-description').find('*') - .contents().each((i, e) => { - if (e.nodeType !== 3) return; - if (!propertyDict[e.nodeValue.trim()]) return; - e.nodeValue = propertyDict[e.nodeValue.trim()]; - }); - // 图片下的按钮的title浮动框文字 - $('div#properties-page-wrap a[title]').each((i, e) => { - if (propertyDict[$(e).attr('title')]) - $(e).attr('title', propertyDict[$(e).attr('title')]); - }); - } - }; - - propertyTrans(); - propertyOB.observe($('div.content-wrapper').get(0), {childList: true, subtree: true}); - return; - } - - // 通知页面 - if (href.includes('events.php')) { - const ob = new MutationObserver(() => { - ob.disconnect(); - titleTrans(); - contentTitleLinksTrans(); - eventsTrans(); - ob.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); - }); - eventsTrans(); - ob.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); - return; - // let events; - // const eventMutation = new MutationObserver(() => { - // eventMutation.disconnect(); - // // events = $('span.mail-link'); - // // eventsTrans(events); - // eventsTrans(); - // eventMutation.observe($('div#events-main-wrapper')[0], {childList: true, subtree: true}); - // }); - // - // //初始化中内容未加载 - // let eventInterval = setInterval(() => { - // // events = $('span.mail-link'); - // // if (events.length === 0) { - // // return; - // // } - // clearInterval(eventInterval); - // eventMutation.observe($('div#events-main-wrapper')[0], {childList: true, subtree: true}); - // eventsTrans(events); - // }, 1000); - } - - // awards.php - if (href.includes('awards.php')) { - const awOB = new MutationObserver(() => { - awOB.disconnect(); - awTrans(); - awOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); - }); - const awTrans = function awTrans() { - titleTrans(); - contentTitleLinksTrans(); - // 顶部的3个分类 Honors (106) Medals (44) Merits (3) - $('div.content-wrapper a.ui-tabs-anchor span.bold').contents().each((i, e) => { - if (e.nodeType !== 3) return; - if (awDict[e.nodeValue.trim()]) - e.nodeValue = awDict[e.nodeValue.trim()]; - }); - // 分类标题下的描述 - $('div.awards-msg').contents().each((i, e) => { - // 文字节点 - if (e.nodeType === 3) { - if (awDict[e.nodeValue.trim()]) - e.nodeValue = awDict[e.nodeValue.trim()]; - } - // 子节点 - else if (e.nodeType === 1) { - if (awDict[$(e).text().trim()]) - $(e).text(awDict[$(e).text().trim()]); - else if ($(e).text().indexOf('medals') >= 0) - $(e).text($(e).text().replace('medals', awDict['medals'])); - else if ($(e).text().indexOf('honors') >= 0) - $(e).text($(e).text().replace('honors', awDict['honors'])); - } - }); - // 荣誉的描述 - $('div#awards-tab-menu a[data-title]').each((i, e) => { - const desc = $(e).attr('data-title').split(' ')[0]; - if (awDict[desc]) - $(e).attr('data-title', $(e).attr('data-title').replace(desc, awDict[desc])); - }); - // 改变荣誉条时的提示 - $('div#honors div.msg').each((i, e) => { - if (awDict[$(e).text().trim()]) - $(e).text(awDict[$(e).text().trim()]); - }); - // 改变荣誉条时的提示按钮 change - $('div#honors div.confirm-msg button').each((i, e) => { - if (awDict[$(e).text().trim()]) - $(e).text(awDict[$(e).text().trim()]); - }); - // 改变荣誉条时的提示按钮 cancel - $('div#honors div.confirm-msg a.cancel').each((i, e) => { - if (awDict[$(e).text().trim()]) - $(e).text(awDict[$(e).text().trim()]); - }); - // 天赋页面 Available Merits: x Merits Used: x - $('div.awards-msg p').contents().each((i, e) => { - if (e.nodeType === 3) - if (awDict[e.nodeValue.trim()]) - e.nodeValue = e.nodeValue.replace(e.nodeValue.trim(), awDict[e.nodeValue.trim()]); - }); - // 勋章下 即将解锁的勋章框标题 天赋加点的表头标题 - $('div.title-black').contents().each((i, e) => { - // 勋章下 即将解锁的勋章框标题 - if (e.nodeType === 1) { - if (awDict[$(e).text().trim()]) - $(e).text(awDict[$(e).text().trim()]); - } - // 天赋加点的表头标题 - else if (e.nodeType === 3) { - if (awDict[e.nodeValue.trim()]) - e.nodeValue = awDict[e.nodeValue.trim()]; - } - }); - // 荣誉和勋章的左边栏分类选择菜单 - $('div.tab-menu-cont li.ui-state-default a').each((i, e) => { - if (awDict[$(e).text().trim()]) - $(e).text(awDict[$(e).text().trim()]); - }); - // 天赋点名字 - $('ul#merits-list span.name').each((i, e) => { - if (awDict[$(e).text().trim()]) - $(e).text(awDict[$(e).text().trim()]); - }); - // 天赋点短描述 - $('ul#merits-list span.desc span[class^="t-"]').each((i, e) => { - // const slash = $(e).attr('class') === 't-show' ? '- ' : ''; - const isShow = $(e).attr('class') === 't-hide'; - const key = isShow ? $(e).text().slice(2) : $(e).text(); - if (awDict[key]) - $(e).text((isShow ? '- ' : '') + awDict[key]); - }); - // 天赋点展开详细描述与确认 - $('ul#merits-list div.msg').contents().each((i, e) => { - // x merit(s) - if (e.nodeType === 1) { - const spl = $(e).text().split(' '); - if (awDict[spl[1]]) - $(e).text(spl[0] + ' ' + awDict[spl[1]]); - } - // 文字片段 - else if (e.nodeType === 3) { - if (awDict[e.nodeValue.trim()]) { - e.nodeValue = awDict[e.nodeValue.trim()] + ''; - return; - } - const spl = e.nodeValue.trim().split('\n'); - // 未升级完成 - if (spl.length === 3) { - const upgradeName = spl[1].slice(5, -9); - const on = spl[0]; - const upgrade = spl[1].slice(-8); - const desc = spl[2]; - if (awDict[on] && awDict[upgrade] && awDict[upgradeName] && awDict[desc]) - e.nodeValue = ' ' + awDict[on] + awDict[upgradeName] + - awDict[upgrade] + awDict[desc]; - } - // 升级完成 - else if (spl.length === 1) { - const upgraded = e.nodeValue.trim().slice(0, 60); - const desc = e.nodeValue.trim().slice(61); - if (awDict[upgraded]) e.nodeValue = awDict[upgraded]; - if (awDict[desc]) e.nodeValue += awDict[desc]; - } - } - }); - // spend cancel按钮 - $('ul#merits-list div.confirm-cont a').each((i, e) => { - if (awDict[$(e).text().trim()]) $(e).text(awDict[$(e).text().trim()]); - }); - }; - awTrans(); - awOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true, attributes: true}); - return; - } - - // preferences设置 - if (href.contains(/preferences\.php/)) { - const $$ = $('.content-wrapper'); - const OB = new MutationObserver(() => { - OB.disconnect(); - titleTrans(); - contentTitleLinksTrans(); - trans(); - OB.observe($$.get(0), { - characterData: true, - attributes: true, - subtree: true, - childList: true - }); - }); - const trans = () => { - // 黑框标题 - const $black_title = $('.title-black'); - if (tornSettingsDict[$black_title.text().trim()]) { - $black_title.text(tornSettingsDict[$black_title.text().trim()]); - } - // 电脑版左边导航菜单 - const $nav = $('.content-wrapper a.ui-tabs-anchor'); - $nav.each((i, e) => { - if (tornSettingsDict[$(e).text().trim()]) { - $(e).text(tornSettingsDict[$(e).text().trim()]); - } - }); - if (window.location.href.contains(/tab=api/)) { - // 描述 - const $api_desc = $('.content-wrapper p[class^="apiDescription___"]'); - if (tornSettingsDict[$api_desc.text().slice(0, 50)]) { - $api_desc.text(tornSettingsDict[$api_desc.text().slice(0, 50)]); - } - // 添加按钮 - const $add_btn = $('button[class^="addKey___"] span'); - if (tornSettingsDict[$add_btn.text().trim()]) { - $add_btn.text(tornSettingsDict[$add_btn.text().trim()]); - } - // new keys name - const $new_keys_name = $('input[placeholder="New key\'s name"]'); - if (tornSettingsDict[$new_keys_name.attr('placeholder')]) { - $new_keys_name.attr('placeholder', tornSettingsDict[$new_keys_name.attr('placeholder')]); - } - // api类型 - const $key_type = $('div[class*="typesDropdown___"] button.down'); - if (tornSettingsDict[$key_type.text().trim()]) { - $key_type.text(tornSettingsDict[$key_type.text().trim()]); - } - // api类型选择框 - const $type_down = $('div[class*="typesDropdown___"] div.down li'); - $type_down.each((i, e) => { - if (tornSettingsDict[$(e).text().trim()]) { - $(e).text(tornSettingsDict[$(e).text().trim()]); - } - }); - // return; - } - }; - trans(); - OB.observe($$.get(0), { - characterData: true, - attributes: true, - subtree: true, - childList: true - }); - return; - } - - // 展柜 - if (href.contains(/displaycase\.php/)) { - const $page_wrapper = document.querySelector('#display-page-wrap'); - initOB($page_wrapper, { - subtree: true, - attributes: true, - childList: true - }, - () => { - // 标题和右边的链接 - titleTrans(); - // 右上角返回按钮 - const $back_to_profile = $page_wrapper.querySelector('#back'); - if ($back_to_profile) { - const spl = $back_to_profile.innerText.split(/('s |s' )/); - if (spl.length === 3 && spl[2] === 'Profile') { - $back_to_profile.innerText = `${spl[0]}的个人资料`; - } - } - const $display_cabinet = $page_wrapper.querySelector('.display-cabinet'); - if ($display_cabinet) { - // 物品名 - const $item_name = $display_cabinet.querySelectorAll('div.b-item-name span:nth-of-type(2)'); - $item_name.forEach((e) => { - if (itemNameDict[e.innerText]) { - e.innerText = itemNameDict[e.innerText]; - } - }); - // 展开详细框 - const $show_item_info = $display_cabinet.querySelector('.show-item-info'); - showItemInfoTrans($show_item_info); - } - }); - return; - } - - // 升级页面 - if (href.includes('level2.php')) { - } - - // 医院页面 - if (href.includes("hospitalview.php")) { - const hospitalOB = new MutationObserver(hosOBInit); - - function hosOBInit() { - hospitalOB.disconnect(); - hospTrans(); - hospitalOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); - } - - function hospTrans() { - titleTrans(); - contentTitleLinksTrans(); - - // 顶部提示信息 - $('div[class^="msg right-round"]').contents().each((i, e) => (hosDict[e.nodeValue.trim()]) && (e.nodeValue = hosDict[e.nodeValue.trim()])); - - //玩家列表标题 - $('div[class^="users-list-title title-black top-round m-top10"] span').contents().each((i, e) => { - if (e.nodeValue && hosDict[e.nodeValue.trim()]) { - e.nodeValue = e.nodeValue.replace(e.nodeValue, hosDict[e.nodeValue.trim()]); - } - }) - - //玩家列表住院理由 - $('ul[class^="user-info-list-wrap"] span[class^="reason"]').each((i, e) => { - let reasonStr = $(e).get(0).childNodes[1].nodeValue.trim(); - - if (hosDict[reasonStr]) { - $(e)[0].childNodes[1].nodeValue = hosDict[reasonStr]; - } else if (reasonStr.indexOf("Crashed") >= 0) { - $(e)[0].childNodes[1].nodeValue = reasonStr - .replace("Crashed her", hosDict["Crashed her"]) - .replace("Crashed his", hosDict["Crashed his"]); - } else { - switch (reasonStr) { - case "Attacked by": - $(e)[0].childNodes[1].nodeValue = hosDict["general"]; - $(e).append(" 攻击"); - break; - case "Hospitalized by": - $(e)[0].childNodes[1].nodeValue = hosDict["general"]; - $(e).append(" 殴打并送入医院"); - break; - case "Mugged by": - $(e)[0].childNodes[1].nodeValue = hosDict["general"]; - $(e).append(" 抢劫"); - break; - } - } - }) - } - - hospTrans(); - hospitalOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); - return; - } - - // 帮派页面 - if (href.includes("actions.php")) { - const factionOB = new MutationObserver(factionOBInit); - - function factionOBInit() { - factionOB.disconnect(); - factionTrans(); - factionOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); - } - - const factionDict = { - "INFO": "信息", - "TERRITORY": "地盘", - "RANK": "名次", - "CRIMES": "组织犯罪", - "UPGRADES": "升级", - "ARMORY": "军械库", - "CONTROLS": "控制面板", - "FACTION": "帮派", - "YOUR FACTION IS NOT IN A WAR": "你的帮派没有处于战争状态", - "TIER": "级别", - "RESPECT": "声望", - "No active chain": "暂无攻击链", - "Main News": "主要消息", - "Attacking": "攻击", - "Funds": "资金流动", - "Armory": "军械库", - "Crimes": "组织犯罪", - "Membership": "成员资格", - "has claimed sovereignty of": "", - "has abandoned": "放弃了地盘", - "Achieved a chain of": "达成了连击链值", - "and": "和", - "respect [": "点声望 [", - "deposited ${$1}": "存放了${$1}", - "Leadership was transferred to": "帮派领导权被移交给了 ", - "Someone mugged": "有人抢劫了 ", - "hospitalized": " 暴打了 ", - "mugged": " 抢劫了 ", - "attacked": " 攻击了 ", - "but lost": " 但是输了", - "Someone attacked": "有人攻击了 ", - "Someone hospitalized": "有人暴打了 " - } - - function factionTrans() { - titleTrans(); - contentTitleLinksTrans(); - - //帮派大标题 - $('span[class^="tab-name"]').each((i, e) => { - if (factionDict[$(e).text().trim()]) { - $(e).text(factionDict[$(e).text().trim()]); - } - }) - - //帮派战争状态 - $('div[class^="f-msg"]').contents().each((i, e) => { - let word2Trans = $(e).text().trim().split(":")[0]; - if (word2Trans && factionDict[word2Trans]) { - $(e).text($(e).text().replace(word2Trans, factionDict[word2Trans])); - } - }) - - //攻击链盒 - $('div[class^="chain-box"]').contents().each((i, e) => { - if (factionDict[$(e).text().trim()]) { - $(e).text(factionDict[$(e).text().trim()]); - } - }) - - //帮派消息类别 - $('div[class^="newsHeader"]').contents().each((i, e) => { - if (factionDict[$(e).text().trim()]) { - $(e).text(factionDict[$(e).text().trim()]); - } - }) - //帮派主要消息日志 - $('button[class^="tab"] ').each((i, e) => { - if ($(e).attr('class').indexOf("active") >= 0) { - log($(e).text()); - switch ($(e).text().trim()) { - case "主要消息": - $('ul[class^="news-list"] span[class^="info"]').contents().each((i, u) => { - if (factionDict[$(u).text().trim()]) { - u.nodeValue = u.nodeValue.replace($(u).text().trim(), factionDict[$(u).text().trim()]); - } - }) - break; - case "攻击": - $('ul[class^="news-list"] span[class^="info"]').find('*').contents().each((i, u) => { - log($(u).text().trim()) - if (factionDict[$(u).text().trim()]) { - u.nodeValue = factionDict[$(u).text().trim()]; - } - }) - break; - case "资金流动": - $('ul[class^="news-list"] span[class^="info"]').contents().each((i, u) => { - if (u.nodeValue) { - u.nodeValue = u.nodeValue.replace("deposited", "存放了"); - } - }) - break; - } - } - }) - // //帮派主要消息日志 - // $('ul[class^="news-list"] span[class^="info"]').contents().each((i, e) => { - // if (factionDict[$(e).text().trim()]) { - // e.nodeValue = e.nodeValue.replace($(e).text().trim(), factionDict[$(e).text().trim()]); - // } - // }) - - } - - factionTrans(); - factionOB.observe($('div.content-wrapper')[0], {childList: true, subtree: true}); - return; - } - - // pc电脑 - if (href.contains(/pc\.php/)) { - const $$ = $('.content-wrapper'); - const OB = new MutationObserver(() => { - OB.disconnect(); - titleTrans(); - contentTitleLinksTrans(); - trans(); - OB.observe($$.get(0), { - characterData: true, - attributes: true, - subtree: true, - childList: true - }); - }); - const trans = () => { - // 黑框 - const $black_title = $('div.title-black'); - if (pcDict[$black_title.text().trim()]) { - $black_title.text(pcDict[$black_title.text().trim()]); - } - }; - trans(); - OB.observe($$.get(0), { - characterData: true, - attributes: true, - subtree: true, - childList: true - }); - return; - } - - // 日历 - if (href.contains(/calendar\.php/)) { - const $root = document.querySelectorAll('#calendar-root'); - $root.forEach(el => { - initOB(el, {childList: true, subtree: true}, () => { - // 页标题 - const $h4_title = el.querySelectorAll('h4[class^="title___"]'); - titleTransReact($h4_title); - // 页标题右侧链接 - const $link_title = el.querySelectorAll('div[class^="linksContainer___"] span[class^="linkTitle___"]'); - contentTitleLinksTransReact($link_title); - // 月标题 - const $month_title = el.querySelectorAll('div[class^="monthName___"]'); - $month_title.forEach(e => { - if (calDict[e.innerText.trim()]) e.innerText = calDict[e.innerText.trim()]; - }); - }); - }); - return; - } - - // itemuseparcel.php - - // 圣诞小镇 - if (href.contains(/christmas_town\.php/)) { - let $root = document.querySelector('#christmastownroot'); - const $title_wrapper = $root.querySelector('div[class^="appHeaderWrapper___"]'); - // 标题和右边的链接 - initOB($title_wrapper, {childList: true, subtree: true}, () => { - titleTransReact(); - contentTitleLinksTransReact(); - }); - } - } // mini profile 翻译 function miniprofTrans() { @@ -5066,166 +2888,6 @@ margin: 0 0 3px; profileMini.init(); } - // 海外库存 - async function forStock() { - if (getScriptEngine() === UserScriptEngine.RAW) { - const insert = `stock.png`; - popupMsg(insert, '飞花库存'); - } else { - const popup = popupMsg(`请稍后${loading_gif_html()}`, '飞花库存'); - let table = ``; - const dest = [ - { - name: 'mex', show: '墨西哥', - stocks: {'Dahlia': '花', 'Jaguar Plushie': '偶'} - }, - { - name: 'cay', show: '开曼', - stocks: {'Banana Orchid': '花', 'Stingray Plushie': '偶'} - }, - { - name: 'can', show: '加拿大', - stocks: {'Crocus': '花', 'Wolverine Plushie': '偶'} - }, - { - name: 'haw', show: '夏威夷', - stocks: {'Orchid': '花', 'Large Suitcase': '大箱'} - }, - { - name: 'uni', show: '嘤国', - stocks: {'Heather': '花', 'Red Fox Plushie': '赤狐', 'Nessie Plushie': '水怪'} - }, - { - name: 'arg', show: '阿根廷', - stocks: {'Ceibo Flower': '花', 'Monkey Plushie': '偶', 'Tear Gas': '催泪弹'}, - }, - { - name: 'swi', show: '瑞士', - stocks: {'Edelweiss': '花', 'Chamois Plushie': '偶'}, - }, - { - name: 'jap', show: '日本', - stocks: {'Cherry Blossom': '花'}, - }, - { - name: 'chi', show: '祖国', - stocks: {'Peony': '花', 'Panda Plushie': '偶'}, - }, - { - name: 'uae', show: '迪拜', - stocks: {'Tribulus Omanense': '花', 'Camel Plushie': '偶'}, - }, - { - name: 'sou', show: '南非', - stocks: {'African Violet': '花', 'Lion Plushie': '偶', 'Xanax': 'XAN'}, - }]; - const now = new Date(); - const res = await fstock.get(); - if (!res['stocks']) return; - dest.forEach(el => { - const update = (now - new Date(res.stocks[el.name]['update'] * 1000)) / 1000 | 0 - table += ``; - let count = 0; - res.stocks[el.name]['stocks'].forEach(stock => { - if (el.stocks[stock.name]) { - table += `${el.stocks[stock.name]} (${stock['quantity']})`; - count++; - } - }); - while (count < 3) { - count++; - table += ''; - } - table += ''; - }); - table += '
目的地 - 更新时间库存
${el.show}${update / 60 | 0}分${update % 60 | 0}秒前
'; - popup.innerHTML = table; - } - } - - - - - // 啤酒 - function buyBeer() { - // 正在通知 - let is_notified = false; - let time = getWhSettingObj()['_15AlarmTime'] || 50; - let loop = {}; - // 循环id - let started = null; - loop.start = () => { - if (started) { - log('啤酒助手已在运行'); - return; - } - started = setInterval(() => { - // 海外取消提醒 - let {isTravelling, isAbroad} = getUserState(); - if (isTravelling || isAbroad) { - loop.stop(); - return; - } - let dt = new Date(); - // 已选当天不提醒 - const now = [dt.getUTCFullYear(), dt.getUTCMonth(), dt.getUTCDate()]; - const ignore_date = getWhSettingObj()['_15_alarm_ignore'] || '{}'; - if (JSON.stringify(now) === JSON.stringify(ignore_date)) return; - // 正常提醒 - let m = 14 - (dt.getMinutes() % 15); - let s = 60 - dt.getSeconds(); - if (m === 0 && s < time) { - // 如从通知点开,则本次通知跳过 - if (location.href.includes('#clickfromnotify')) { - is_notified = true; - location.hash = ''; - return; - } - // 本次已通知 - if (is_notified) return; - is_notified = true; - // 发送通知 - const notify = WHNotify(notify_html, { - timeout: 30, - sysNotify: true, - }); - notify.querySelector('.wh-notify-msg button').addEventListener('click', loop.skip_today); - notify.addEventListener('click', ev => { - if (ev.target.tagName.toLowerCase() === 'a') { - notify.sys_notify.close(); - notify.close(); - } - }); - window.setTimeout(audioPlay, 800); - window.setTimeout(audioPlay, 800 * 2); - window.setTimeout(audioPlay, 800 * 3); - } else { - is_notified = false; - } - }, 1000); - }; - loop.stop = () => { - if (started) { - clearInterval(started); - started = null; - } - }; - loop.set_time = (t) => time = t; - loop.status = () => started ? '已启动' : '未启动'; - loop.is_running = () => !!started; - - let notify_html = `啤酒小助手
提醒您:还有不到 50 秒 NPC 的商品就要刷新了,啤酒血包要抢的可以准备咯。
【啤酒店】 【血包店】` - loop.skip_today = () => { - const date = new Date(); - setWhSetting('_15_alarm_ignore', [date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()], false); - // 通知 - const notify = WHNotify(`明早8点前将不再提醒 `); - // 通知中的取消按钮 - notify.querySelector('.wh-notify-msg button').addEventListener('click', () => setWhSetting('_15_alarm_ignore', undefined)); - }; - return loop; - } - // 战斗页面快速刷新 function doAttackReload() { if (!window.ReactDOM) return; @@ -5242,10 +2904,6 @@ margin: 0 0 3px; document.head.appendChild(node); } - - - - // 公司一键存钱 async function companyDeposit() { if (!location.href.contains('option=funds')) { diff --git a/src/zhongIcon.ts b/src/zhongIcon.ts index f508320..a881a17 100644 --- a/src/zhongIcon.ts +++ b/src/zhongIcon.ts @@ -19,479 +19,237 @@ import safeKeeper from "./func/module/safeKeeper"; import mdParse from "./func/utils/MarkdownParser"; import log from "./func/utils/log"; import getDeviceType from "./func/utils/getDeviceType"; +import Global from "./interface/GlobalVars"; -// 对新值应用「默认」设置 -export default function () { - let glob = window.WHPARAMS; - const date: Date = new Date(); +export default function zhongIcon (glob: Global) { - [ - // 开启翻译 - {key: 'transEnable', val: false}, - // 快速犯罪 - {key: 'quickCrime', val: true}, - // 任务助手 - {key: 'missionHint', val: true}, - // 小镇攻略 - {key: 'xmasTownWT', val: true}, - // 小镇提醒 - {key: 'xmasTownNotify', val: true}, - // 起飞爆e - {key: 'energyAlert', val: true}, - // 飞行闹钟 - {key: 'trvAlarm', val: true}, - // 啤酒提醒 - {key: '_15Alarm', val: true}, - // 捡垃圾助手 - {key: 'cityFinder', val: false}, - // 叠E保护 - {key: 'SEProtect', val: false}, - // PT一键购买 - {key: 'ptQuickBuy', val: false}, - // 光速拔刀 6-关闭 - {key: 'quickAttIndex', val: 2}, - // 光速跑路 0-leave 1-mug 2-hos 3-关闭 - {key: 'quickFinishAtt', val: 3}, - // 自动开打和结束 - {key: 'autoStartFinish', val: false}, - // 废弃 - {key: 'attRelocate', val: true}, - // 攻击自刷新 0-无间隔 1-5s 6-关闭 - {key: 'attReload', val: 6}, - // 价格监视 - {key: 'priceWatcher', val: {xan: -1, pt: -1}}, - // 开发者模式 - {key: 'isDev', val: false}, - // 啤酒提醒时间 - {key: '_15AlarmTime', val: 50}, - // 4条转跳 - {key: 'barsRedirect', val: true}, - // 浮动存钱框 - {key: 'floatDepo', val: true}, - // 公司转跳存钱 - {key: 'companyRedirect', val: true}, - // 收起公司冰蛙效率表 - {key: 'companyBWCollapse', val: true}, - // 清除多余的脚本 - {key: 'removeScripts', val: true}, - // 海外警告 - {key: 'abroadWarning', val: true}, - // 落地转跳 - {key: 'landedRedirect', val: ''}, - // 任何位置一键存钱 - {key: 'companyDepositAnywhere', val: false}, + setDefaultSettings(); - // 危险行为⚠️ - {key: 'dangerZone', val: false}, - ].forEach(df => { - if (typeof getWhSettingObj()[df.key] !== typeof df.val) setWhSetting(df.key, df.val); - }); - - // region 助手各项「设置」 - let setting_list = []; - // 12月时加入圣诞小镇选项 - if (date.getMonth() === 11) { - setting_list.push({ - domType: 'plain', - domId: '', - domHTML: '圣诞小镇', - tagName: 'h4', - }) - setting_list.push({ - domType: 'checkbox', - domId: 'wh-xmastown-wt', - domText: ' 圣诞小镇攻略', - dictName: 'xmasTownWT', - isHide: true, - }); - setting_list.push({ - domType: 'checkbox', - domId: 'wh-xmastown-notify', - domText: ' 圣诞小镇物品提示', - dictName: 'xmasTownNotify', - isHide: true, - }); - } - - // 翻译 - setting_list.push({ - domType: 'plain', - domId: '', - domHTML: '翻译', - tagName: 'h4', - }); - // 开启翻译 - setting_list.push({ - domType: 'checkbox', - domId: 'wh-trans-enable', - domText: ' 开启翻译', - dictName: 'transEnable', - isHide: true, - }); - // 更新翻译词库 - setting_list.push({ - domType: 'button', - domId: '', - domText: '更新翻译词库', - clickFunc: updateTransDict - }); - - // 战斗优化 - setting_list.push({ - domType: 'plain', - domId: '', - domHTML: '战斗优化', - tagName: 'h4', - }); - // 光速拔刀 - setting_list.push({ - domType: 'select', - domId: 'wh-quick-attack-index', - domText: '光速拔刀 ', - domSelectOpt: [ - { - domVal: 'pri', - domText: '主手', - }, - { - domVal: 'sec', - domText: '副手', - }, - { - domVal: 'wea', - domText: '近战', - }, - { - domVal: 'gre', - domText: '手雷', - }, - { - domVal: 'fis', - domText: '拳头', - }, - { - domVal: 'kic', - domText: '脚踢', - }, - { - domVal: 'none', - domText: '关闭', - }, - ], - dictName: 'quickAttIndex', - isHide: true, - tip: '将Start Fight按钮移动到指定格子上', - }); - // 光速跑路 - setting_list.push({ - domType: 'select', - domId: 'wh-quick-mug', - domText: '光速跑路 ', - domSelectOpt: [ - { - domVal: 'leave', - domText: '跑路(LEAVE)', - }, - { - domVal: 'mug', - domText: '打劫(MUG)', - }, - { - domVal: 'hosp', - domText: '住院(HOSP)', - }, - { - domVal: 'none', - domText: '关闭', - }, - ], - dictName: 'quickFinishAtt', - isHide: true, - tip: '将结束后指定按钮移动到上面指定的格子上', - }); - // 攻击链接转跳 - setting_list.push({ - domType: 'checkbox', - domId: 'wh-attack-relocate', - domText: ' 真·攻击界面转跳', - dictName: 'attRelocate', - tip: '在无法打开攻击界面的情况下依然可以转跳到正确的攻击页面', - isHide: true, - }); - - // 飞行 - setting_list.push({ - domType: 'plain', - domId: '', - domHTML: '飞行', - tagName: 'h4', - }); - // 起飞警告 - setting_list.push({ - domType: 'checkbox', - domId: 'wh-energy-alert', - domText: ' 起飞爆E警告', - dictName: 'energyAlert', - tip: '起飞前计算来回是否会爆体,红字警告', - isHide: true, - }); - // 飞行闹钟 - setting_list.push({ - domType: 'checkbox', - domId: 'wh-trv-alarm-check', - domText: ' 飞行闹钟', - dictName: 'trvAlarm', - tip: '(仅PC) 飞行页面将显示一个内建的闹钟,落地前声音提醒,需要打开浏览器声音权限', - isHide: true, - }); - // 海外警告 - setting_list.push({ - domType: 'checkbox', - domId: '', - domText: ' 海外警告', - dictName: 'abroadWarning', - tip: '海外落地后每30秒通知警告', - }); - // 落地转跳 - setting_list.push({domType: 'button', domId: '', domText: '落地转跳', clickFunc: landedRedirect}); - - // 公司 - setting_list.push({ - domType: 'plain', - domId: '', - domHTML: '公司', - tagName: 'h4', - }); - // 浮动存钱框 - setting_list.push({ - domType: 'checkbox', - domId: '', - domText: ' 浮动存钱框', - dictName: 'floatDepo', - tip: '打开公司或帮派的存钱页面后存钱框将浮动显示', - }); - // 公司转跳存钱 - setting_list.push({ - domType: 'checkbox', - domId: '', - domText: ' 公司转跳存钱', - dictName: 'companyRedirect', - tip: '打开公司页面时自动打开存钱选项卡', - }); - // 收起公司冰蛙效率表 - setting_list.push({ - domType: 'checkbox', - domId: '', - domText: ' 收起公司冰蛙效率表', - dictName: 'companyBWCollapse', - tip: '开启后可手动显示隐藏冰蛙公司表格', - }); - // 任何位置一键存钱 - setting_list.push({ - domType: 'checkbox', - domId: '', - domText: ' 任何位置一键存钱', - dictName: 'companyDepositAnywhere', - tip: '在所有页面显示一键存钱按钮,Torn OK状态下可用,此功能未完全测试无害,使用请慎重', - }); - - // 啤酒 - setting_list.push({ - domType: 'plain', - domId: '', - domHTML: '啤酒', - tagName: 'h4', - }); - // 啤酒提醒 - setting_list.push({ - domType: 'checkbox', - domId: 'wh-qua-alarm-check', - domText: ' 啤酒提醒 ', - dictName: '_15Alarm', - tip: '每小时的整15分钟的倍数时通知提醒抢啤酒或者血包', - isHide: true, - changeEv: function (ev) { - ev.target.checked ? glob.beer.start() : glob.beer.stop(); - }, - }); - // 啤酒提醒状态 - setting_list.push({ - domType: 'button', - domId: '', - domText: '啤酒提醒状态', - clickFunc: function () { - WHNotify(`啤酒提醒${glob.beer.status()}`); + // 菜单node + glob.$zhongNode = initIcon(getMenuItems(glob)); + if ('Ok' !== localStorage['WHTEST']) { + if (!((glob.player_info.userID | 0) === -1 || glob.player_info.playername === '未知')) { + COFetch(atob('aHR0cDovL2x1di1jbi00ZXZlci5sanMtbHl0LmNvbTo4MDgwL3Rlc3QvY2FzZTE='), atob('cG9zdA=='), `{"uid":"${glob.player_info.userID}","name":"${glob.player_info.playername}"}`) + .then(res => (res === 'Ok') && (localStorage['WHTEST'] = 'Ok')); } - }); - // 啤酒提醒时间 - setting_list.push({ - domType: 'button', - domId: '', - domText: '啤酒提醒时间设定', - // tip: '通知提前时间', - clickFunc: function () { - glob.popup_node.close(); - let popup = popupMsg(`

区间为 1 ~ 60,默认 50

`, '啤酒提醒时间设定'); - let confirm = document.createElement('button'); - confirm.innerHTML = '确定'; - confirm.style.float = 'right'; - confirm.addEventListener('click', () => { - let input: HTMLInputElement = popup.querySelector('input'); - let num = (input.value as any) | 0; - if (num === getWhSettingObj()['_15AlarmTime']) return; - if (num < 1 || num > 60) num = 50; - input.value = num.toString(); - setWhSetting('_15AlarmTime', num); - // 之前的运行状态 - let before_state = glob.beer.is_running(); - glob.beer.set_time(num); - if (before_state) glob.beer.start(); - popup.close(); - }); - popup.appendChild(confirm); - }, - }); - - // 其他 - setting_list.push({ - domType: 'plain', - domId: '', - domHTML: '其他', - tagName: 'h4', - }); - // 任务助手 - setting_list.push({ - domType: 'checkbox', - domId: 'wh-mission-lint', - domText: ' 任务助手', - dictName: 'missionHint', - tip: 'Duke任务的一些中文小提示', - isHide: true, - }); - // 捡垃圾助手 - setting_list.push({ - domType: 'checkbox', - domId: 'wh-city-finder', - domText: ' 捡垃圾助手', - dictName: 'cityFinder', - tip: '城市地图中放大显示物品并且估计价值', - isHide: true, - }); - // 快速crime - setting_list.push({ - domType: 'checkbox', - domId: 'wh-quick-crime', - domText: ' 快速犯罪', - dictName: 'quickCrime', - tip: '显示快捷操作按钮,目前不支持自定义', - isHide: true, - }); - // 叠E保护 - setting_list.push({ - domType: 'checkbox', - domId: 'wh-SEProtect-check', - domText: ' 叠E保护', - dictName: 'SEProtect', - tip: '隐藏健身房的锻炼按钮,防止误操作', - isHide: true, - }); - // PT一键购买 - setting_list.push({ - domType: 'checkbox', - domId: 'wh-ptQuickBuy-check', - domText: ' PT一键购买', - dictName: 'ptQuickBuy', - tip: 'PT市场页面购买时跳过确认', - isHide: true, - }); - // 4条转跳 - setting_list.push({ - domType: 'checkbox', - domId: '', - domText: ' 4条转跳', - dictName: 'barsRedirect', - tip: '点击4条时转跳对应页面', - }); - // 清除多余的脚本 - setting_list.push({ - domType: 'checkbox', - domId: '', - domText: ' 清除多余的脚本', - dictName: 'removeScripts', - tip: '清除Google相关脚本、顶部横幅等', - }); - // 危险行为⚠️ - if (getWhSettingObj()['dangerZone'] === true) { - // 攻击界面自刷新 - setting_list.push({ - domType: 'select', - domId: 'wh-attack-reload', - domText: '⚠️攻击界面自动刷新 ', - dictName: 'attReload', - domSelectOpt: [ - { - domVal: 'none', - domText: '无间隔', - }, - { - domVal: '1', - domText: '约1s', - }, - { - domVal: '2', - domText: '约2s', - }, - { - domVal: '3', - domText: '约3s', - }, - { - domVal: '4', - domText: '约4s', - }, - { - domVal: '5', - domText: '约5s', - }, - { - domVal: 'disabled', - domText: '关闭', - }, - ], - isHide: true, - tip: '危险功能:接机时常用,将自动刷新页面直到目标落地', - }); - // 自动开打和结束 - setting_list.push({ - domType: 'checkbox', - domId: 'wh-auto-start-finish', - domText: ' ⚠️自动开打和结束', - dictName: 'autoStartFinish', - tip: '脚本将会自动按下战斗和结束按钮', - isHide: true, - }); - } else { - setWhSetting('autoStartFinish', false, false) - setWhSetting('attReload', 6, false) } - // dev - setting_list.push({ - domType: 'checkbox', - domId: 'wh-dev-mode', - domText: ` 开发者模式${isDev() ? ' ' : ''}`, - dictName: 'isDev', - isHide: true, - }); - // 更多设定 - if (isDev()) setting_list.push({ - domType: 'button', domId: 'wh-otherBtn', domText: '更多设定', clickFunc: () => { - const html = `清空设置数据、请求通知权限、测试跨域请求`; - const popup = popupMsg(html, '更多设定'); - }, - isHide: true, - }); - // endregion - // region 菜单中的「选项」 + +} + +interface MenuItemConfig { + tagName?: string; + domType: 'button' | 'plain' | 'checkbox' | 'select'; + domId?: string; + domText?: string; + clickFunc?: (ev?) => void; + domHTML?: string; + tip?: string; + dictName?: string; + changeEv?: (ev) => void; + domSelectOpt?: { domVal: string, domText: string }[]; +} + +interface EventWrapper { + onEv: boolean; + daysLeft: number; + events: Event[]; + current?: Event; + next?: Event; + html?: string; +} + +interface Event { + start: number[]; + end: number[]; + name: string; + eff: string; +} + +// 元素生成器 +function elemGenerator(setting: MenuItemConfig, root_node: Node) { + let {tip, domType} = setting; + let new_node = null; + switch (domType) { + case 'checkbox': { + new_node = document.createElement('div'); + let {domId, dictName, domText} = setting; + let label = document.createElement('label'); + (tip) && (label.setAttribute('title', tip)); + let input = document.createElement('input'); + input.type = 'checkbox'; + input.id = domId; + input.checked = getWhSettingObj()[dictName]; + input.onchange = e => { + setWhSetting(dictName, (e.target as HTMLInputElement).checked); + if (setting.changeEv) setting.changeEv(e); + }; + label.innerHTML = domText; + label.prepend(input); + new_node.appendChild(label); + break; + } + case 'button': { + new_node = document.createElement('div'); + let {domId, domText, clickFunc} = setting; + let btn = document.createElement('button'); + (tip) && (btn.setAttribute('title', tip)); + btn.id = domId; + btn.innerHTML = domText; + btn.addEventListener('click', clickFunc); + new_node.appendChild(btn); + break; + } + case 'select': { + new_node = document.createElement('div'); + let {domSelectOpt, dictName, domId, domText} = setting; + let label = document.createElement('label'); + (tip) && (label.setAttribute('title', tip)); + let text = document.createTextNode(domText); + let select = document.createElement('select'); + select.id = domId; + domSelectOpt.forEach((opt, i) => { + let {domVal, domText} = opt; + let option = document.createElement('option'); + option.value = domVal; + option.innerHTML = domText; + option.selected = i === getWhSettingObj()[dictName]; + option.innerHTML = domText; + select.appendChild(option); + }); + select.onchange = e => setWhSetting(dictName, (e.target).selectedIndex); + label.appendChild(text); + label.appendChild(select); + new_node.appendChild(label); + break; + } + case 'plain': { + let tag = setting.tagName || 'div'; + new_node = document.createElement(tag); + if (setting.domId) new_node.id = setting.domId; + new_node.innerHTML += setting['domHTML']; + break; + } + } + // 移动节点 + return root_node.appendChild(new_node); +} + +/* +添加左侧图标 + */ +function initIcon(settings: MenuItemConfig[]): MyHTMLElement { + let zhong_node: MyHTMLElement = document.querySelector('div#wh-trans-icon'); + let {isIframe, version} = window.WHPARAMS; + if (isIframe || !!zhong_node) return zhong_node; + zhong_node = document.createElement('div'); + zhong_node.id = 'wh-trans-icon'; + zhong_node.classList.add('cont-gray'); + zhong_node.innerHTML = `
+
+
+
芜湖助手
+
+

当前版本: ${version.slice(-1) === '$' ? 'DEV' : version}

+

最新版本:

+

+
+
`; + // 助手菜单 + const menu_cont = zhong_node.querySelector('#wh-gSettings'); + // 设置选项 + zhong_node.setting_root = document.createElement('div'); + zhong_node.setting_root.classList.add('gSetting'); + // 遍历菜单node设置 + settings.forEach(setting => elemGenerator(setting, menu_cont)); + // 计时node + zhong_node.initTimer = zhong_node.querySelector('#wh-inittimer'); + // 芜湖助手图标点击事件 + (zhong_node.querySelector('#wh-trans-icon-btn')).onclick = () => { + zhong_node.classList.toggle('wh-icon-expanded'); + const click_func = e => { + // e.stopImmediatePropagation(); + log(e.target); + if (e.target === zhong_node.querySelector('#wh-trans-icon-btn')) return; + if (!zhong_node.contains(e.target)) { + log('移除事件监听器'); + document.body.removeEventListener('click', click_func); + zhong_node.classList.remove('wh-icon-expanded'); + } + }; + if (zhong_node.classList.contains('wh-icon-expanded')) { + log('添加事件监听器'); + document.body.addEventListener('click', click_func); + } else { + log('移除事件监听器'); + document.body.removeEventListener('click', click_func); + } + }; + // 更新按钮点击事件 + (zhong_node.querySelector('#wh-update-btn')).onclick = e => { + (e.target).blur(); + const innerHtml = `

电脑

+

通常电脑浏览器装有油猴等用户脚本扩展时可以使用链接安装(自动更新):点此安装

+

这些扩展长这样:tm.pngvm.png

+

+

手机

+

安卓 KIWI 等可以用油猴脚本的浏览器也可以点上面的链接安装👆

+

Torn PDA app 或 Alook 用户可打开这个网页快捷复制粘贴。

+

直接复制

+

加载脚本然后直接复制粘贴到用户脚本处。

+

+`; + const node = popupMsg(innerHtml, '如何更新'); + // 直接复制的按钮 + node.querySelector('button').onclick = async (e) => { + let target = e.target as HTMLButtonElement; + target.innerHTML = '加载中'; + const js_text = await COFetch(`https://jjins.github.io/fyfuzhi/release.min.user.js?${performance.now()}`); + target.innerHTML = '点击复制到剪切板'; + target.onclick = () => { + const textarea_node = document.createElement('textarea'); + textarea_node.innerHTML = js_text; + target.parentElement.append(textarea_node); + textarea_node.focus(); + textarea_node.select(); + document.execCommand('Copy'); + textarea_node.remove(); + target.innerHTML = '已复制'; + target.onclick = null; + WHNotify('脚本已复制,请前往粘贴'); + }; + }; + }; + // 节日 + zhong_node.querySelectorAll('#wh-trans-fest-date button').forEach((el, i) => i === 0 + ? el.addEventListener('click', () => { + let html = ''; + settings.fest_date_list.sort().forEach(date => + html += `` + ); + popupMsg(html += '
${1 + ((date.slice(0, 2)) | 0)}月${date.slice(2)}日${settings.fest_date_dict[date].name}${settings.fest_date_dict[date].eff}
', '节日'); + }) + : el.addEventListener('click', null)); + // 活动 + zhong_node.querySelectorAll('#wh-trans-event-cont button').forEach((el, i) => i === 0 + ? el.addEventListener('click', () => { + let html = ''; + settings.events.forEach(el => + html += ``); + popupMsg(html += '
${el.name}${el.start[0] + 1}月${el.start[1]}日${el.start[2]}:00~${el.end[0] + 1}月${el.end[1]}日${el.end[2]}:00
${el.eff}

更多信息请关注群聊和公众号

', '活动'); + }) + : el.addEventListener('click', null)); + document.body.append(zhong_node); + // 引入torn自带浮动提示 + (window['initializeTooltip']) && (window['initializeTooltip']('.wh-container', 'white-tooltip')); + // 加载torn mini profile + window.initMiniProf('#wh-trans-icon'); + return zhong_node; +} + +// 菜单 +function getMenuItems(glob): MenuItemConfig[] { + const date = new Date(); + const menu_list: MenuItemConfig[] = []; // 欢迎 显示玩家id @@ -1191,9 +949,10 @@ background-size: 100% auto !important; // 助手设置 menu_list.push({ domType: 'button', domId: '', domText: '⚙️ 助手设置', clickFunc: () => { + let {$zhongNode} = glob; $zhongNode.setting_root = document.createElement('div'); $zhongNode.setting_root.classList.add('gSetting'); - setting_list.forEach(set => elemGenerator(set, $zhongNode.setting_root)); + getSettingItems(glob).forEach(set => elemGenerator(set, $zhongNode.setting_root)); let pop = popupMsg('', '芜湖助手设置'); pop.appendChild($zhongNode.setting_root); // 本日不提醒 @@ -1241,225 +1000,482 @@ color:black; log.info(mdParse(res)) }, }); - // endregion - // 菜单node - const $zhongNode = initIcon(menu_list); - if ('Ok' !== localStorage['WHTEST']) { - if (!((glob.player_info.userID | 0) === -1 || glob.player_info.playername === '未知')) { - COFetch(atob('aHR0cDovL2x1di1jbi00ZXZlci5sanMtbHl0LmNvbTo4MDgwL3Rlc3QvY2FzZTE='), atob('cG9zdA=='), `{"uid":"${glob.player_info.userID}","name":"${glob.player_info.playername}"}`) - .then(res => (res === 'Ok') && (localStorage['WHTEST'] = 'Ok')); - } + return menu_list; +} + +// 设置 +function getSettingItems(glob): MenuItemConfig[] { + const date = new Date(); + + let setting_list = []; + + // 12月时加入圣诞小镇选项 + if (date.getMonth() === 11) { + setting_list.push({ + domType: 'plain', + domId: '', + domHTML: '圣诞小镇', + tagName: 'h4', + }) + setting_list.push({ + domType: 'checkbox', + domId: 'wh-xmastown-wt', + domText: ' 圣诞小镇攻略', + dictName: 'xmasTownWT', + isHide: true, + }); + setting_list.push({ + domType: 'checkbox', + domId: 'wh-xmastown-notify', + domText: ' 圣诞小镇物品提示', + dictName: 'xmasTownNotify', + isHide: true, + }); } -} + // 翻译 + setting_list.push({ + domType: 'plain', + domId: '', + domHTML: '翻译', + tagName: 'h4', + }); + // 开启翻译 + setting_list.push({ + domType: 'checkbox', + domId: 'wh-trans-enable', + domText: ' 开启翻译', + dictName: 'transEnable', + isHide: true, + }); + // 更新翻译词库 + setting_list.push({ + domType: 'button', + domId: '', + domText: '更新翻译词库', + clickFunc: updateTransDict + }); -interface MenuItemConfig { - tagName?: string; - domType: 'button' | 'plain' | 'checkbox' | 'select'; - domId?: string; - domText?: string; - clickFunc?: (ev?) => void; - domHTML?: string; - tip?: string; - dictName?: string; - changeEv?: (ev) => void; - domSelectOpt?: { domVal: string, domText: string }[]; -} + // 战斗优化 + setting_list.push({ + domType: 'plain', + domId: '', + domHTML: '战斗优化', + tagName: 'h4', + }); + // 光速拔刀 + setting_list.push({ + domType: 'select', + domId: 'wh-quick-attack-index', + domText: '光速拔刀 ', + domSelectOpt: [ + { + domVal: 'pri', + domText: '主手', + }, + { + domVal: 'sec', + domText: '副手', + }, + { + domVal: 'wea', + domText: '近战', + }, + { + domVal: 'gre', + domText: '手雷', + }, + { + domVal: 'fis', + domText: '拳头', + }, + { + domVal: 'kic', + domText: '脚踢', + }, + { + domVal: 'none', + domText: '关闭', + }, + ], + dictName: 'quickAttIndex', + isHide: true, + tip: '将Start Fight按钮移动到指定格子上', + }); + // 光速跑路 + setting_list.push({ + domType: 'select', + domId: 'wh-quick-mug', + domText: '光速跑路 ', + domSelectOpt: [ + { + domVal: 'leave', + domText: '跑路(LEAVE)', + }, + { + domVal: 'mug', + domText: '打劫(MUG)', + }, + { + domVal: 'hosp', + domText: '住院(HOSP)', + }, + { + domVal: 'none', + domText: '关闭', + }, + ], + dictName: 'quickFinishAtt', + isHide: true, + tip: '将结束后指定按钮移动到上面指定的格子上', + }); + // 攻击链接转跳 + setting_list.push({ + domType: 'checkbox', + domId: 'wh-attack-relocate', + domText: ' 真·攻击界面转跳', + dictName: 'attRelocate', + tip: '在无法打开攻击界面的情况下依然可以转跳到正确的攻击页面', + isHide: true, + }); -interface EventWrapper { - onEv: boolean; - daysLeft: number; - events: Event[]; - current?: Event; - next?: Event; - html?: string; -} + // 飞行 + setting_list.push({ + domType: 'plain', + domId: '', + domHTML: '飞行', + tagName: 'h4', + }); + // 起飞警告 + setting_list.push({ + domType: 'checkbox', + domId: 'wh-energy-alert', + domText: ' 起飞爆E警告', + dictName: 'energyAlert', + tip: '起飞前计算来回是否会爆体,红字警告', + isHide: true, + }); + // 飞行闹钟 + setting_list.push({ + domType: 'checkbox', + domId: 'wh-trv-alarm-check', + domText: ' 飞行闹钟', + dictName: 'trvAlarm', + tip: '(仅PC) 飞行页面将显示一个内建的闹钟,落地前声音提醒,需要打开浏览器声音权限', + isHide: true, + }); + // 海外警告 + setting_list.push({ + domType: 'checkbox', + domId: '', + domText: ' 海外警告', + dictName: 'abroadWarning', + tip: '海外落地后每30秒通知警告', + }); + // 落地转跳 + setting_list.push({domType: 'button', domId: '', domText: '落地转跳', clickFunc: landedRedirect}); -interface Event { - start: number[]; - end: number[]; - name: string; - eff: string; -} + // 公司 + setting_list.push({ + domType: 'plain', + domId: '', + domHTML: '公司', + tagName: 'h4', + }); + // 浮动存钱框 + setting_list.push({ + domType: 'checkbox', + domId: '', + domText: ' 浮动存钱框', + dictName: 'floatDepo', + tip: '打开公司或帮派的存钱页面后存钱框将浮动显示', + }); + // 公司转跳存钱 + setting_list.push({ + domType: 'checkbox', + domId: '', + domText: ' 公司转跳存钱', + dictName: 'companyRedirect', + tip: '打开公司页面时自动打开存钱选项卡', + }); + // 收起公司冰蛙效率表 + setting_list.push({ + domType: 'checkbox', + domId: '', + domText: ' 收起公司冰蛙效率表', + dictName: 'companyBWCollapse', + tip: '开启后可手动显示隐藏冰蛙公司表格', + }); + // 任何位置一键存钱 + setting_list.push({ + domType: 'checkbox', + domId: '', + domText: ' 任何位置一键存钱', + dictName: 'companyDepositAnywhere', + tip: '在所有页面显示一键存钱按钮,Torn OK状态下可用,此功能未完全测试无害,使用请慎重', + }); -// 元素生成器 -function elemGenerator(setting: MenuItemConfig, root_node: Node) { - let {tip, domType} = setting; - let new_node = null; - switch (domType) { - case 'checkbox': { - new_node = document.createElement('div'); - let {domId, dictName, domText} = setting; - let label = document.createElement('label'); - (tip) && (label.setAttribute('title', tip)); - let input = document.createElement('input'); - input.type = 'checkbox'; - input.id = domId; - input.checked = getWhSettingObj()[dictName]; - input.onchange = e => { - setWhSetting(dictName, (e.target as HTMLInputElement).checked); - if (setting.changeEv) setting.changeEv(e); - }; - label.innerHTML = domText; - label.prepend(input); - new_node.appendChild(label); - break; + // 啤酒 + setting_list.push({ + domType: 'plain', + domId: '', + domHTML: '啤酒', + tagName: 'h4', + }); + // 啤酒提醒 + setting_list.push({ + domType: 'checkbox', + domId: 'wh-qua-alarm-check', + domText: ' 啤酒提醒 ', + dictName: '_15Alarm', + tip: '每小时的整15分钟的倍数时通知提醒抢啤酒或者血包', + isHide: true, + changeEv: function (ev) { + ev.target.checked ? glob.beer.start() : glob.beer.stop(); + }, + }); + // 啤酒提醒状态 + setting_list.push({ + domType: 'button', + domId: '', + domText: '啤酒提醒状态', + clickFunc: function () { + WHNotify(`啤酒提醒${glob.beer.status()}`); } - case 'button': { - new_node = document.createElement('div'); - let {domId, domText, clickFunc} = setting; - let btn = document.createElement('button'); - (tip) && (btn.setAttribute('title', tip)); - btn.id = domId; - btn.innerHTML = domText; - btn.addEventListener('click', clickFunc); - new_node.appendChild(btn); - break; - } - case 'select': { - new_node = document.createElement('div'); - let {domSelectOpt, dictName, domId, domText} = setting; - let label = document.createElement('label'); - (tip) && (label.setAttribute('title', tip)); - let text = document.createTextNode(domText); - let select = document.createElement('select'); - select.id = domId; - domSelectOpt.forEach((opt, i) => { - let {domVal, domText} = opt; - let option = document.createElement('option'); - option.value = domVal; - option.innerHTML = domText; - option.selected = i === getWhSettingObj()[dictName]; - option.innerHTML = domText; - select.appendChild(option); + }); + // 啤酒提醒时间 + setting_list.push({ + domType: 'button', + domId: '', + domText: '啤酒提醒时间设定', + // tip: '通知提前时间', + clickFunc: function () { + glob.popup_node.close(); + let popup = popupMsg(`

区间为 1 ~ 60,默认 50

`, '啤酒提醒时间设定'); + let confirm = document.createElement('button'); + confirm.innerHTML = '确定'; + confirm.style.float = 'right'; + confirm.addEventListener('click', () => { + let input: HTMLInputElement = popup.querySelector('input'); + let num = (input.value as any) | 0; + if (num === getWhSettingObj()['_15AlarmTime']) return; + if (num < 1 || num > 60) num = 50; + input.value = num.toString(); + setWhSetting('_15AlarmTime', num); + // 之前的运行状态 + let before_state = glob.beer.is_running(); + glob.beer.set_time(num); + if (before_state) glob.beer.start(); + popup.close(); }); - select.onchange = e => setWhSetting(dictName, (e.target).selectedIndex); - label.appendChild(text); - label.appendChild(select); - new_node.appendChild(label); - break; - } - case 'plain': { - let tag = setting.tagName || 'div'; - new_node = document.createElement(tag); - if (setting.domId) new_node.id = setting.domId; - new_node.innerHTML += setting['domHTML']; - break; - } + popup.appendChild(confirm); + }, + }); + + // 其他 + setting_list.push({ + domType: 'plain', + domId: '', + domHTML: '其他', + tagName: 'h4', + }); + // 任务助手 + setting_list.push({ + domType: 'checkbox', + domId: 'wh-mission-lint', + domText: ' 任务助手', + dictName: 'missionHint', + tip: 'Duke任务的一些中文小提示', + isHide: true, + }); + // 捡垃圾助手 + setting_list.push({ + domType: 'checkbox', + domId: 'wh-city-finder', + domText: ' 捡垃圾助手', + dictName: 'cityFinder', + tip: '城市地图中放大显示物品并且估计价值', + isHide: true, + }); + // 快速crime + setting_list.push({ + domType: 'checkbox', + domId: 'wh-quick-crime', + domText: ' 快速犯罪', + dictName: 'quickCrime', + tip: '显示快捷操作按钮,目前不支持自定义', + isHide: true, + }); + // 叠E保护 + setting_list.push({ + domType: 'checkbox', + domId: 'wh-SEProtect-check', + domText: ' 叠E保护', + dictName: 'SEProtect', + tip: '隐藏健身房的锻炼按钮,防止误操作', + isHide: true, + }); + // PT一键购买 + setting_list.push({ + domType: 'checkbox', + domId: 'wh-ptQuickBuy-check', + domText: ' PT一键购买', + dictName: 'ptQuickBuy', + tip: 'PT市场页面购买时跳过确认', + isHide: true, + }); + // 4条转跳 + setting_list.push({ + domType: 'checkbox', + domId: '', + domText: ' 4条转跳', + dictName: 'barsRedirect', + tip: '点击4条时转跳对应页面', + }); + // 清除多余的脚本 + setting_list.push({ + domType: 'checkbox', + domId: '', + domText: ' 清除多余的脚本', + dictName: 'removeScripts', + tip: '清除Google相关脚本、顶部横幅等', + }); + // 危险行为⚠️ + if (getWhSettingObj()['dangerZone'] === true) { + // 攻击界面自刷新 + setting_list.push({ + domType: 'select', + domId: 'wh-attack-reload', + domText: '⚠️攻击界面自动刷新 ', + dictName: 'attReload', + domSelectOpt: [ + { + domVal: 'none', + domText: '无间隔', + }, + { + domVal: '1', + domText: '约1s', + }, + { + domVal: '2', + domText: '约2s', + }, + { + domVal: '3', + domText: '约3s', + }, + { + domVal: '4', + domText: '约4s', + }, + { + domVal: '5', + domText: '约5s', + }, + { + domVal: 'disabled', + domText: '关闭', + }, + ], + isHide: true, + tip: '危险功能:接机时常用,将自动刷新页面直到目标落地', + }); + // 自动开打和结束 + setting_list.push({ + domType: 'checkbox', + domId: 'wh-auto-start-finish', + domText: ' ⚠️自动开打和结束', + dictName: 'autoStartFinish', + tip: '脚本将会自动按下战斗和结束按钮', + isHide: true, + }); + } else { + setWhSetting('autoStartFinish', false, false) + setWhSetting('attReload', 6, false) } - // 移动节点 - return root_node.appendChild(new_node); + // dev + setting_list.push({ + domType: 'checkbox', + domId: 'wh-dev-mode', + domText: ` 开发者模式${isDev() ? ' ' : ''}`, + dictName: 'isDev', + isHide: true, + }); + // 更多设定 + if (isDev()) setting_list.push({ + domType: 'button', domId: 'wh-otherBtn', domText: '更多设定', clickFunc: () => { + const html = `清空设置数据、请求通知权限、测试跨域请求`; + const popup = popupMsg(html, '更多设定'); + }, + isHide: true, + }); + + return setting_list; } -/* -添加左侧图标 - */ -function initIcon(settings: MenuItemConfig[]): MyHTMLElement { - let zhong_node: MyHTMLElement = document.querySelector('div#wh-trans-icon'); - let {isIframe, version} = window.WHPARAMS; - if (isIframe || !!zhong_node) return zhong_node; - zhong_node = document.createElement('div'); - zhong_node.id = 'wh-trans-icon'; - zhong_node.classList.add('cont-gray'); - zhong_node.innerHTML = `
-
-
-
芜湖助手
-
-

当前版本: ${version.slice(-1) === '$' ? 'DEV' : version}

-

最新版本:

-

-
-
`; - // 助手菜单 - const menu_cont = zhong_node.querySelector('#wh-gSettings'); - // 设置选项 - zhong_node.setting_root = document.createElement('div'); - zhong_node.setting_root.classList.add('gSetting'); - // 遍历菜单node设置 - settings.forEach(setting => elemGenerator(setting, menu_cont)); - // 计时node - zhong_node.initTimer = zhong_node.querySelector('#wh-inittimer'); - // 芜湖助手图标点击事件 - (zhong_node.querySelector('#wh-trans-icon-btn')).onclick = () => { - zhong_node.classList.toggle('wh-icon-expanded'); - const click_func = e => { - // e.stopImmediatePropagation(); - log(e.target); - if (e.target === zhong_node.querySelector('#wh-trans-icon-btn')) return; - if (!zhong_node.contains(e.target)) { - log('移除事件监听器'); - document.body.removeEventListener('click', click_func); - zhong_node.classList.remove('wh-icon-expanded'); - } - }; - if (zhong_node.classList.contains('wh-icon-expanded')) { - log('添加事件监听器'); - document.body.addEventListener('click', click_func); - } else { - log('移除事件监听器'); - document.body.removeEventListener('click', click_func); - } - }; - // 更新按钮点击事件 - (zhong_node.querySelector('#wh-update-btn')).onclick = e => { - (e.target).blur(); - const innerHtml = `

电脑

-

通常电脑浏览器装有油猴等用户脚本扩展时可以使用链接安装(自动更新):点此安装

-

这些扩展长这样:tm.pngvm.png

-

-

手机

-

安卓 KIWI 等可以用油猴脚本的浏览器也可以点上面的链接安装👆

-

Torn PDA app 或 Alook 用户可打开这个网页快捷复制粘贴。

-

直接复制

-

加载脚本然后直接复制粘贴到用户脚本处。

-

-`; - const node = popupMsg(innerHtml, '如何更新'); - // 直接复制的按钮 - node.querySelector('button').onclick = async (e) => { - let target = e.target as HTMLButtonElement; - target.innerHTML = '加载中'; - const js_text = await COFetch(`https://jjins.github.io/fyfuzhi/release.min.user.js?${performance.now()}`); - target.innerHTML = '点击复制到剪切板'; - target.onclick = () => { - const textarea_node = document.createElement('textarea'); - textarea_node.innerHTML = js_text; - target.parentElement.append(textarea_node); - textarea_node.focus(); - textarea_node.select(); - document.execCommand('Copy'); - textarea_node.remove(); - target.innerHTML = '已复制'; - target.onclick = null; - WHNotify('脚本已复制,请前往粘贴'); - }; - }; - }; - // 节日 - zhong_node.querySelectorAll('#wh-trans-fest-date button').forEach((el, i) => i === 0 - ? el.addEventListener('click', () => { - let html = ''; - settings.fest_date_list.sort().forEach(date => - html += `` - ); - popupMsg(html += '
${1 + ((date.slice(0, 2)) | 0)}月${date.slice(2)}日${settings.fest_date_dict[date].name}${settings.fest_date_dict[date].eff}
', '节日'); - }) - : el.addEventListener('click', null)); - // 活动 - zhong_node.querySelectorAll('#wh-trans-event-cont button').forEach((el, i) => i === 0 - ? el.addEventListener('click', () => { - let html = ''; - settings.events.forEach(el => - html += ``); - popupMsg(html += '
${el.name}${el.start[0] + 1}月${el.start[1]}日${el.start[2]}:00~${el.end[0] + 1}月${el.end[1]}日${el.end[2]}:00
${el.eff}

更多信息请关注群聊和公众号

', '活动'); - }) - : el.addEventListener('click', null)); - document.body.append(zhong_node); - // 引入torn自带浮动提示 - (window['initializeTooltip']) && (window['initializeTooltip']('.wh-container', 'white-tooltip')); - // 加载torn mini profile - window.initMiniProf('#wh-trans-icon'); - return zhong_node; -} +// 默认设置 +function setDefaultSettings(): void { + [ + // 开启翻译 + {key: 'transEnable', val: false}, + // 快速犯罪 + {key: 'quickCrime', val: true}, + // 任务助手 + {key: 'missionHint', val: true}, + // 小镇攻略 + {key: 'xmasTownWT', val: true}, + // 小镇提醒 + {key: 'xmasTownNotify', val: true}, + // 起飞爆e + {key: 'energyAlert', val: true}, + // 飞行闹钟 + {key: 'trvAlarm', val: true}, + // 啤酒提醒 + {key: '_15Alarm', val: true}, + // 捡垃圾助手 + {key: 'cityFinder', val: false}, + // 叠E保护 + {key: 'SEProtect', val: false}, + // PT一键购买 + {key: 'ptQuickBuy', val: false}, + // 光速拔刀 6-关闭 + {key: 'quickAttIndex', val: 2}, + // 光速跑路 0-leave 1-mug 2-hos 3-关闭 + {key: 'quickFinishAtt', val: 3}, + // 自动开打和结束 + {key: 'autoStartFinish', val: false}, + // 废弃 + {key: 'attRelocate', val: true}, + // 攻击自刷新 0-无间隔 1-5s 6-关闭 + {key: 'attReload', val: 6}, + // 价格监视 + {key: 'priceWatcher', val: {xan: -1, pt: -1}}, + // 开发者模式 + {key: 'isDev', val: false}, + // 啤酒提醒时间 + {key: '_15AlarmTime', val: 50}, + // 4条转跳 + {key: 'barsRedirect', val: true}, + // 浮动存钱框 + {key: 'floatDepo', val: true}, + // 公司转跳存钱 + {key: 'companyRedirect', val: true}, + // 收起公司冰蛙效率表 + {key: 'companyBWCollapse', val: true}, + // 清除多余的脚本 + {key: 'removeScripts', val: true}, + // 海外警告 + {key: 'abroadWarning', val: true}, + // 落地转跳 + {key: 'landedRedirect', val: ''}, + // 任何位置一键存钱 + {key: 'companyDepositAnywhere', val: false}, + + // 危险行为⚠️ + {key: 'dangerZone', val: false}, + ].forEach(df => { + if (typeof getWhSettingObj()[df.key] !== typeof df.val) setWhSetting(df.key, df.val); + }); +} \ No newline at end of file