476 lines
19 KiB
TypeScript
476 lines
19 KiB
TypeScript
import adHelper from "../func/module/adHelper";
|
|
import safeKeeper from "../func/module/safeKeeper";
|
|
import initMiniProf from "../func/utils/initMiniProf";
|
|
import WuhuBase from "./WuhuBase";
|
|
import Log from "./Log";
|
|
import CommonUtils from "./utils/CommonUtils";
|
|
import Alert from "./utils/Alert";
|
|
import * as EVENTS from "../static/json/event.json";
|
|
import * as FEST from "../static/json/fest.json";
|
|
import Popup from "./utils/Popup";
|
|
import TravelItem from "./action/TravelItem";
|
|
import ZHONG_MENU_HTML from "../static/html/zhong/zhong_menu.html";
|
|
import ZHONG_UPDATE_HTML from "../static/html/zhong/zhong_update.html";
|
|
import ZHONG_LOOT_HTML from "../static/html/zhong/zhong_loot.html";
|
|
import Test from "../test/Test";
|
|
import Global from "./Global";
|
|
import Timer from "./utils/Timer";
|
|
import QuickFlyBtnHandler from "./handler/QuickFlyBtnHandler";
|
|
import NNB from "./handler/NNB";
|
|
import QuickLinksHandler from "./handler/QuickLinksHandler";
|
|
import ItemPriceWatcherHandler from "./handler/ItemPriceWatcherHandler";
|
|
import ChangeLogHandler from "./handler/ChangeLogHandler";
|
|
import SettingsHandler from "./handler/SettingsHandler";
|
|
import WuhuConfig from "./WuhuConfig";
|
|
|
|
export default class ZhongIcon extends WuhuBase {
|
|
className = 'ZhongIcon';
|
|
public static ZhongNode: MyHTMLElement = null;
|
|
private menuItemList: MenuItemConfig[] = null;
|
|
private cashView: HTMLElement = null;
|
|
|
|
// private settingItemList: MenuItemConfig[] = null;
|
|
|
|
public constructor() {
|
|
super();
|
|
}
|
|
|
|
public init() {
|
|
Log.info('ZhongIcon初始化, 设置图标开始');
|
|
this.constructMenuList()
|
|
.insert2Dom()
|
|
.dragHandler();
|
|
Log.info('设置图标结束, ZhongIcon初始化结束');
|
|
}
|
|
|
|
private static setPosition(x: number, y: number) {
|
|
if (!(x && y)) return;
|
|
if (x > 0 && x < document.documentElement.offsetWidth - 100) {
|
|
ZhongIcon.ZhongNode.style.left = x + "px";
|
|
}
|
|
if (y > 0 && y < document.documentElement.offsetHeight - 60) {
|
|
ZhongIcon.ZhongNode.style.top = y + "px";
|
|
}
|
|
}
|
|
|
|
public updateCashView(content: string): void {
|
|
if (!this.cashView || !ZhongIcon.ZhongNode.contains(this.cashView)) {
|
|
this.cashView = document.createElement('div');
|
|
this.cashView.id = 'wh-cash-monitor';
|
|
ZhongIcon.ZhongNode.append(this.cashView);
|
|
}
|
|
this.cashView.innerText = content;
|
|
}
|
|
|
|
/**
|
|
* 添加左侧图标
|
|
*/
|
|
private insert2Dom(): ZhongIcon {
|
|
let zhongNode: MyHTMLElement = document.querySelector('div#wh-trans-icon');
|
|
let settings = this.menuItemList;
|
|
let { version } = WuhuBase.glob;
|
|
if ((self !== top) || !!zhongNode) return null;
|
|
zhongNode = document.createElement('div');
|
|
ZhongIcon.ZhongNode = zhongNode;
|
|
zhongNode.id = 'wh-trans-icon';
|
|
zhongNode.classList.add('cont-gray');
|
|
zhongNode.innerHTML = ZHONG_MENU_HTML.replace('{{}}', version.slice(-1) === '$' ? 'DEV' : version);
|
|
// 助手菜单
|
|
const menu_cont = zhongNode.querySelector('#wh-gSettings');
|
|
// 遍历菜单node设置、生成node、插入dom
|
|
this.menuItemList.forEach(setting => CommonUtils.getInstance().elemGenerator(setting, menu_cont));
|
|
Log.info('生成元素插入完成');
|
|
// 计时node
|
|
zhongNode.initTimer = zhongNode.querySelector('#wh-inittimer');
|
|
// 芜湖助手图标点击事件
|
|
(<MyHTMLElement>zhongNode.querySelector('#wh-trans-icon-btn')).onclick = () => {
|
|
zhongNode.classList.toggle('wh-icon-expanded');
|
|
const click_func = e => {
|
|
Log.info(e.target);
|
|
if (e.target === zhongNode.querySelector('#wh-trans-icon-btn')) return;
|
|
if (!zhongNode.contains(e.target)) {
|
|
Log.info('移除事件监听器');
|
|
document.body.removeEventListener('click', click_func);
|
|
zhongNode.classList.remove('wh-icon-expanded');
|
|
}
|
|
};
|
|
if (zhongNode.classList.contains('wh-icon-expanded')) {
|
|
Log.info('芜湖助手图标点击->添加监听');
|
|
document.body.addEventListener('click', click_func);
|
|
} else {
|
|
Log.info('芜湖助手图标->移除监听');
|
|
document.body.removeEventListener('click', click_func);
|
|
}
|
|
};
|
|
// 更新按钮点击事件
|
|
(<MyHTMLElement>zhongNode.querySelector('#wh-update-btn')).onclick = e => {
|
|
(<HTMLButtonElement>e.target).blur();
|
|
const innerHtml = ZHONG_UPDATE_HTML;
|
|
// 直接复制的按钮
|
|
new Popup(innerHtml, '如何更新')
|
|
.getElement()
|
|
.querySelector('button').onclick = async (e) => {
|
|
let target = e.target as HTMLButtonElement;
|
|
target.innerHTML = '加载中';
|
|
const js_text = await CommonUtils.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;
|
|
new Alert('脚本已复制,请前往粘贴');
|
|
};
|
|
};
|
|
};
|
|
// 节日
|
|
zhongNode.querySelectorAll('#wh-trans-fest-date button').forEach((el, i) => i === 0
|
|
? el.addEventListener('click', () => {
|
|
let html = '<table>';
|
|
settings.fest_date_list.sort().forEach(date =>
|
|
html += `<tr><td>${ 1 + ((<any>date.slice(0, 2)) | 0) }月${ date.slice(2) }日</td><td>${ settings.fest_date_dict[date].name }</td><td>${ settings.fest_date_dict[date].eff }</td></tr>`
|
|
);
|
|
new Popup(html += '</table>', '节日');
|
|
})
|
|
: el.addEventListener('click', null));
|
|
// 活动
|
|
zhongNode.querySelectorAll('#wh-trans-event-cont button').forEach((el, i) => i === 0
|
|
? el.addEventListener('click', () => {
|
|
let html = '<table>';
|
|
settings.events.forEach(el =>
|
|
html += `<tr><td><b>${ el.name }</b></td><td>${ el.start[0] + 1 }月${ el.start[1] }日${ el.start[2] }:00~${ el.end[0] + 1 }月${ el.end[1] }日${ el.end[2] }:00</td></tr><tr><td colspan="2">${ el.eff }</td></tr>`);
|
|
new Popup(html += '</table><p>更多信息请关注群聊和公众号</p>', '活动');
|
|
})
|
|
: el.addEventListener('click', null));
|
|
// 调整图标至有记录的位置
|
|
if (WuhuConfig.get("SaveIconPosition")) {
|
|
let iconPosition = WuhuConfig.get("IconPosition");
|
|
let documentSize = { x: document.documentElement.offsetWidth, y: document.documentElement.offsetHeight };
|
|
ZhongIcon.setPosition(
|
|
iconPosition.x > documentSize.x ? documentSize.x * 0.9 | 0 : iconPosition.x,
|
|
iconPosition.y > documentSize.y ? documentSize.y * 0.9 | 0 : iconPosition.y
|
|
);
|
|
}
|
|
document.body.append(zhongNode);
|
|
// 引入torn自带浮动提示
|
|
Log.info('引入torn自带浮动提示');
|
|
(window.initializeTooltip) && (window.initializeTooltip('.wh-container', 'white-tooltip'));
|
|
// 加载torn mini profile
|
|
Log.info('加载torn mini profile');
|
|
let miniProfileInterval = {
|
|
id: window.setInterval(() => {
|
|
miniProfileInterval.counter++;
|
|
if (window.$ || (window.unsafeWindow && window.unsafeWindow.$)) {
|
|
initMiniProf('#wh-trans-icon');
|
|
window.clearInterval(miniProfileInterval.id);
|
|
}
|
|
if (miniProfileInterval.counter > 30) window.clearInterval(miniProfileInterval.id);
|
|
}, 1000),
|
|
counter: 0
|
|
};
|
|
Log.info('图标加入文档树完成');
|
|
return this;
|
|
}
|
|
|
|
private dragHandler(): ZhongIcon {
|
|
let isMouseDown = false;
|
|
let isMouseMoved = false;
|
|
let offsetXY = { x: 0, y: 0 };
|
|
ZhongIcon.ZhongNode.addEventListener('mousedown', (e) => {
|
|
if (e.button === 0) {
|
|
e.preventDefault();
|
|
isMouseDown = true;
|
|
let nodeXY = ZhongIcon.getPosition();
|
|
offsetXY.x = e.x - nodeXY.x;
|
|
offsetXY.y = e.y - nodeXY.y;
|
|
}
|
|
});
|
|
document.addEventListener('mouseup', () => {
|
|
isMouseDown = false;
|
|
if (isMouseMoved) {
|
|
isMouseMoved = false;
|
|
if (WuhuConfig.get("SaveIconPosition")) {
|
|
WuhuConfig.set("IconPosition", ZhongIcon.getPosition());
|
|
}
|
|
}
|
|
});
|
|
document.addEventListener('mousemove', (e) => {
|
|
if (isMouseDown) {
|
|
ZhongIcon.setPosition(e.x - offsetXY.x, e.y - offsetXY.y);
|
|
isMouseMoved = true;
|
|
}
|
|
});
|
|
return this;
|
|
}
|
|
|
|
private static getPosition(): { x: number, y: number } {
|
|
return {
|
|
x: ZhongIcon.ZhongNode.style.left ? parseInt(ZhongIcon.ZhongNode.style.left.slice(0, -2)) : ZhongIcon.ZhongNode.offsetLeft,
|
|
y: ZhongIcon.ZhongNode.style.top ? parseInt(ZhongIcon.ZhongNode.style.top.slice(0, -2)) : ZhongIcon.ZhongNode.offsetTop
|
|
}
|
|
}
|
|
|
|
// 菜单
|
|
private constructMenuList(): ZhongIcon {
|
|
Log.info('构造展开菜单列表开始');
|
|
let timer = new Timer();
|
|
let glob = Global.getInstance();
|
|
const date = new Date();
|
|
|
|
let list: MenuItemConfig[] = [];
|
|
|
|
// 欢迎 显示玩家id
|
|
if (glob.player_info.userID !== 0) {
|
|
list.push({
|
|
domType: 'plain',
|
|
domId: 'wh-trans-welcome',
|
|
domHTML: `<a href="/profiles.php?XID=${ glob.player_info.userID }" target="_blank">${ glob.player_info.playername }</a>[${ glob.player_info.userID }]`,
|
|
});
|
|
}
|
|
// 节日
|
|
let fest_date_html = '<button>节日</button>: ';
|
|
{
|
|
// 节日字典
|
|
const dict = FEST.val;
|
|
list.fest_date_dict = dict;
|
|
list.fest_date_list = Object.keys(dict);
|
|
const formatMMDD = (m, d) => {
|
|
const MM = m < 10 ? `0${ m }` : m.toString();
|
|
const DD = d < 10 ? `0${ d }` : d.toString();
|
|
return MM + DD;
|
|
}
|
|
const fest_date_key = formatMMDD(date.getUTCMonth(), date.getUTCDate());
|
|
if (dict[fest_date_key]) fest_date_html += `今天 - ${ dict[fest_date_key]['name'] }(<button title="${ dict[fest_date_key]['eff'] }">效果</button>)`;
|
|
else {
|
|
// 月日列表
|
|
let list = Object.keys(dict);
|
|
list.push(fest_date_key);
|
|
// 下个节日的位置
|
|
const index: number = list.sort().indexOf(fest_date_key) + 1;
|
|
// 下个节日obj
|
|
const next_fest_date = dict[list[index] || list[0]];
|
|
// 下个节日的时间
|
|
let next = new Date(
|
|
index !== list.length ? date.getUTCFullYear() : date.getUTCFullYear() + 1,
|
|
(list[index !== list.length ? index : 0] as any).slice(0, 2) | 0,
|
|
(list[index !== list.length ? index : 0] as any).slice(2) | 0,
|
|
8
|
|
).getTime();
|
|
// 剩余天数
|
|
const left = (next - date.getTime()) / 86400000 | 0;
|
|
fest_date_html += `${ left }天后 - ${ next_fest_date.name }(<button title="${ next_fest_date.eff }">效果</button>)`;
|
|
}
|
|
}
|
|
list.push({
|
|
domType: 'plain',
|
|
domId: 'wh-trans-fest-date',
|
|
domHTML: fest_date_html,
|
|
});
|
|
// 活动
|
|
let eventObj: EventWrapper = {
|
|
onEv: false,
|
|
daysLeft: Infinity,
|
|
events: EVENTS.default,
|
|
};
|
|
list.events = eventObj.events;
|
|
eventObj.events.forEach((obj, index) => {
|
|
if (eventObj.onEv) return;
|
|
// 当前年份
|
|
const nowYear = date.getFullYear();
|
|
// 当前遍历的活动开始时间
|
|
const start = new Date(nowYear, obj.start[0], obj.start[1], obj.start[2]);
|
|
// 当前遍历的活动结束时间
|
|
const end = new Date(nowYear, obj.end[0], obj.end[1], obj.end[2]);
|
|
// 当前处于活动中
|
|
if (start < date && date < end) {
|
|
eventObj.onEv = true;
|
|
eventObj.daysLeft = (end.getTime() - date.getTime()) / 86400000 | 0;
|
|
eventObj.current = obj;
|
|
}
|
|
// 当前没有活动
|
|
else {
|
|
// 当前遍历的活动如果已经经过了,那么下次活动就是遍历的下一个活动对象,否则为当前活动。
|
|
// 如果本年度活动都经过了,那么下次活动是列表的第一个活动对象
|
|
const next = end < date ? eventObj.events[index + 1] || eventObj.events[0] : obj;
|
|
// 经过了最后一个活动所以下次活动开始时间是第二年
|
|
const start = new Date(next !== obj && index === eventObj.events.length - 1 ? nowYear + 1 : nowYear, next.start[0], next.start[1], next.start[2]);
|
|
const daysLeft = (start.getTime() - date.getTime()) / 86400000 | 0;
|
|
if (0 <= daysLeft && daysLeft < eventObj.daysLeft) {
|
|
eventObj.daysLeft = daysLeft;
|
|
eventObj.next = next;
|
|
}
|
|
}
|
|
});
|
|
eventObj.html = '<button>活动</button>: ';
|
|
eventObj.onEv
|
|
? eventObj.html += `${ eventObj.current.name }(<button title="${ eventObj.current.eff }">详情</button>) - 剩余${ eventObj.daysLeft }天`
|
|
: eventObj.html += `${ eventObj.daysLeft }天后 - ${ eventObj.next.name }(<button title="${ eventObj.next.eff }">详情</button>)`;
|
|
list.push({
|
|
domType: 'plain',
|
|
domId: 'wh-trans-event-cont',
|
|
domHTML: eventObj.html,
|
|
});
|
|
// 一键起飞
|
|
list.push({
|
|
domType: 'button',
|
|
domId: 'wh-quick-fly-btn',
|
|
domText: '✈️ 一键起飞',
|
|
clickFunc: () => QuickFlyBtnHandler.getInstance().handle(),
|
|
});
|
|
// 飞花库存
|
|
list.push({
|
|
domType: 'button',
|
|
domId: 'wh-foreign-stock-btn',
|
|
domText: '🌸 飞花库存',
|
|
clickFunc: () => TravelItem.getInstance().clickHandler().then(),
|
|
});
|
|
// NPC LOOT
|
|
list.push({
|
|
domType: 'button',
|
|
domId: 'wh-npc-loot-btn',
|
|
domText: '🔫 LOOT',
|
|
clickFunc: () => {
|
|
const insert = ZHONG_LOOT_HTML.replace('{{}}', performance.now().toString());
|
|
new Popup(insert, 'NPC LOOT');
|
|
},
|
|
tip: '显示5个可击杀NPC的开打时间',
|
|
});
|
|
// 查看NNB
|
|
list.push({
|
|
domType: 'button',
|
|
domId: 'wh-nnb-info',
|
|
domText: '👮 查看NNB',
|
|
clickFunc: () => NNB.getInstance().handle(),
|
|
});
|
|
// 常用链接
|
|
list.push({
|
|
domType: 'button',
|
|
domId: 'wh-link-collection',
|
|
domText: '🔗 常用链接',
|
|
clickFunc: () => QuickLinksHandler.getInstance().handle()
|
|
});
|
|
// 飞贼
|
|
// list.push({
|
|
// domType: 'button',
|
|
// domId: 'wh-gs-btn',
|
|
// domText: '🐏 飞贼小助手',
|
|
// clickFunc: () => loadGS(CommonUtils.getScriptEngine()),
|
|
// tip: '加载从PC端移植的伞佬的油猴版飞贼小助手',
|
|
// });
|
|
|
|
// 物品价格监视
|
|
list.push({
|
|
domType: 'button',
|
|
domId: 'wh-price-watcher-btn',
|
|
domText: '💊 价格监视',
|
|
clickFunc: () => ItemPriceWatcherHandler.getInstance().handle()
|
|
});
|
|
// 全屏
|
|
if (!Global.getInstance().isPDA) list.push({
|
|
domType: 'button', domId: '', domText: '🖥️ 进入全屏', clickFunc() {
|
|
document.documentElement.requestFullscreen().then();
|
|
}
|
|
});
|
|
// 传单助手
|
|
list.push({
|
|
domType: 'button',
|
|
domId: '',
|
|
domText: '📜️ 传单助手',
|
|
clickFunc: adHelper
|
|
});
|
|
// 守望者
|
|
list.push({
|
|
domType: 'button',
|
|
domId: '',
|
|
domText: '🛡️ 守望者',
|
|
clickFunc: function () {
|
|
safeKeeper();
|
|
},
|
|
});
|
|
// 寻找木桩
|
|
list.push({
|
|
domType: 'button',
|
|
domId: '',
|
|
domText: '🌲 寻找木桩',
|
|
clickFunc() {
|
|
window.location.replace('https://www.torn.com/item.php?temp=4#xunzhaomuzhuang')
|
|
}
|
|
});
|
|
// 更新历史
|
|
list.push({
|
|
domType: 'button',
|
|
domId: '',
|
|
domText: '🐞 更新历史',
|
|
clickFunc: async () => ChangeLogHandler.getInstance().handle()
|
|
});
|
|
// 助手设置
|
|
list.push({
|
|
domType: 'button',
|
|
domId: '',
|
|
domText: '⚙️ 助手设置',
|
|
clickFunc: () => SettingsHandler.getInstance().handler(),
|
|
});
|
|
// 测试
|
|
if (Log.debug()) list.push({
|
|
domType: 'button',
|
|
domId: '',
|
|
domText: '📐️ 测试',
|
|
clickFunc: async function () {
|
|
let startTime = performance.now();
|
|
Log.info('测试开始');
|
|
try {
|
|
Test.getInstance().test();
|
|
} catch (e) {
|
|
Log.error('测试异常,' + JSON.stringify(e));
|
|
}
|
|
|
|
Log.info('测试结束 ' + ((performance.now() - startTime) | 0) + 'ms');
|
|
},
|
|
});
|
|
|
|
this.menuItemList = list;
|
|
Log.info('构造展开菜单列表结束' + timer.getTimeMs());
|
|
return this;
|
|
}
|
|
}
|
|
|
|
export interface MenuItemConfig {
|
|
domType: 'button' | 'plain' | 'checkbox' | 'select';
|
|
tagName?: string;
|
|
domId?: string;
|
|
domText?: string;
|
|
clickFunc?: (ev?) => void;
|
|
domHTML?: string;
|
|
tip?: string;
|
|
dictName?: string;
|
|
changeEv?: (ev) => void;
|
|
domSelectOpt?: { domVal: string, domText: string }[];
|
|
/**
|
|
* 隐藏菜单已弃用
|
|
* @deprecated
|
|
*/
|
|
isHide?: boolean;
|
|
isTornBtn?: boolean;
|
|
}
|
|
|
|
interface EventWrapper {
|
|
onEv: boolean;
|
|
daysLeft: number;
|
|
events: Event[];
|
|
current?: Event;
|
|
next?: Event;
|
|
html?: string;
|
|
}
|
|
|
|
interface Event {
|
|
start: number[];
|
|
end: number[];
|
|
name: string;
|
|
eff: string;
|
|
}
|