// ==UserScript==
// @name TransferLog Search & Balance
// @author Neleus
// @namespace Neleus
// @description HWM TransferLog Search with balance calculation
// @version 1.2
// @include /^https?:\/\/(www|mirror|my)?\.?(heroeswm|lordswm)\.(ru|com)\/pl_transfers\.php.*/
// @grant none
// @run-at document-end
// @license GNU GPLv3
// ==/UserScript==
(function () {
// Constants
const SELECTORS = {
CONTAINER_HEADER: "global_container_block_header global_a_hover",
GLOBAL_HOVER: "global_a_hover",
};
const ELEMENT_IDS = {
STOP: "stop",
SEARCH_DIV: "transferSearchDiv",
SEARCH_STATUS: "TSearch",
CHECKBOX_LABEL: "HWM_transfer_search_checkbox_label",
SHOW_BLOCK: "show_transfer_block",
};
const INPUT_IDS = {
NICK: "TSearchNick",
ART: "TSearchArt",
ALL: "TSearchAll",
PAGE_FROM: "TSearch_inp_page_from",
PAGE_TO: "TSearch_inp_page_to",
};
const SEARCH_TYPES = {
NICK: "Nick",
FINE: "Fine",
ART: "Art",
ANY: "Any",
};
const DATE_TIME_PATTERN = "[0-9]{2}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}";
// Global variables
const url = location.protocol + "//" + location.hostname + "/";
const playerId = getPlayerId();
const hiddenDiv = createHiddenDiv();
let searchBalance = 0; // Общий баланс найденных операций
let totalBalance = 0; // Общий баланс всех операций на странице
// Initialize
// Глобальная функция для остановки поиска
window.stopSearch = function () {
const stopButton = $(ELEMENT_IDS.STOP);
if (stopButton) {
stopButton.value = "1";
}
};
const rootElement = findRootElement();
applyInitialColoringAndBalance();
createSearchInterface(rootElement);
setupEventListeners(rootElement);
// Balance Processing Functions
function makeColoredLine(line, gold, color) {
return `<span style='background:rgba(${
color === "green" ? "100,255,100,.1" : "255,100,100,.1"
})'>${line} <b style='color:${color}'>${gold}</b></span>`;
}
function parseTransferLines(htmlContent) {
const matches = [];
const regex = /( .+?)<br>/g;
let match;
while ((match = regex.exec(htmlContent)) !== null) {
matches.push(match[1]);
}
return matches;
}
// Применяем раскраску и баланс при загрузке страницы (как в старом скрипте)
function applyInitialColoringAndBalance() {
const transferDiv = rootElement.getElementsByClassName("global_a_hover")[0];
if (!transferDiv) return;
const originalHTML = transferDiv.innerHTML;
if (
originalHTML.includes("<span style=") &&
originalHTML.includes("Баланс золота:")
) {
return;
}
const bodyHTML = document.body.innerHTML;
const lines = parseTransferLines(bodyHTML);
let html = "";
totalBalance = 0;
let processedCount = 0;
for (let line of lines) {
if (line.trim()) {
const { processedLine, goldAmount } = processTransferBalance(line);
html += processedLine + "<br>";
totalBalance += goldAmount;
processedCount++;
}
}
if (lines.length > 0) {
transferDiv.innerHTML = html;
transferDiv.insertAdjacentHTML(
"beforeend",
`<br><b style='padding:20px'>Баланс золота: <span style='color:${
totalBalance < 0 ? "red" : "green"
}'>${totalBalance > 0 ? "+" : ""}${totalBalance.toLocaleString(
"en-US"
)}</span></b>`
);
}
}
function extractOriginalText(coloredLine) {
if (!coloredLine || !coloredLine.includes("<span style=")) {
return coloredLine;
}
return coloredLine
.replace(/<span[^>]*>/g, "")
.replace(/<\/span>/g, "")
.replace(/<b[^>]*>.*?<\/b>/g, "")
.replace(/ /g, " ")
.trim();
}
function cleanLineForParsing(line) {
return line.replace(/<[^>]*>/g, "");
}
function extractGoldAmount(line, pattern, isNegative = false) {
const cleanLine = cleanLineForParsing(line);
const match = pattern.exec(cleanLine);
if (match) {
const amount = +match[1];
return isNegative ? -amount : amount;
}
return 0;
}
function extractGoldWithCommission(
line,
goldPattern,
commissionPattern,
isNegative = false
) {
const cleanLine = cleanLineForParsing(line);
const goldMatch = goldPattern.exec(cleanLine);
const commissionMatch = commissionPattern
? commissionPattern.exec(cleanLine)
: null;
if (goldMatch) {
let amount = +goldMatch[1];
if (commissionMatch) {
amount -= +commissionMatch[1];
}
return isNegative ? -amount : amount;
}
return 0;
}
function processTransferBalance(line) {
let gold = 0;
let newline = line;
try {
// Обмен бриллиантов на золото: "10 бриллиантов обменяно на 50000 золота"
if (/обменян/.test(line)) {
gold = extractGoldAmount(line, /на (?:<b>)?(\d+)/);
newline = makeColoredLine(line, "+" + gold, "green");
}
// Продажи и передачи с комиссией
else if (/(?:Передан .+?за \d+ (?:Золото|золота)|Продан)/.test(line)) {
gold = extractGoldWithCommission(
line,
/за (\d+) (?:золота|Золото)/,
/комиссия:* (\d+)/
);
newline = makeColoredLine(line, "+" + gold, "green");
}
// Передача предмета с получением золота
else if (/Передан предмет.*Получено: \d+ золота/.test(line)) {
gold = extractGoldAmount(line, /Получено: (\d+) золота/);
newline = makeColoredLine(line, "+" + gold, "green");
}
// Получение предмета и золота за ремонт
else if (/Получен .+?на ремонт/.test(line)) {
const cleanLine = cleanLineForParsing(line);
const g = /ремонт: (\d+)/.exec(cleanLine)?.[1];
const p = /(\d+)%/.exec(cleanLine)?.[1];
if (g && p) {
gold = Math.ceil(g / p) * (p - 100);
newline = makeColoredLine(
line,
gold >= 0 ? "+" + gold : gold,
gold >= 0 ? "green" : "red"
);
}
}
// Оплата за ремонт
else if (/Оплачено за/.test(line)) {
gold = extractGoldWithCommission(
line,
/ремонт: (\d+)/,
/комиссия: (\d+)/,
true
);
newline = makeColoredLine(line, gold, "red");
}
// Аренда артефакта
else if (/Арендован/.test(line)) {
gold = extractGoldWithCommission(
line,
/Стоимость: (\d+)/,
/комиссия: (\d+)/,
true
);
newline = makeColoredLine(line, gold, "red");
}
// Получение золота, заработок, обмен бриллиантов
else if (
/Получено \d+ (?:Золото|золота)\s+от|Взято|Заработано|бриллиант[ао]в? обменяно на \d+ золота/.test(
line
)
) {
gold = extractGoldAmount(line, /(\d+) (?:Золото|золота)/);
newline = makeColoredLine(line, "+" + gold, "green");
}
// Взят в ремонт
else if (/Взят в ремонт/.test(line)) {
gold = extractGoldAmount(line, /Заработано: (\d+)/);
newline = makeColoredLine(line, "+" + gold, "green");
}
// Передача денег в клан
else if (/Передано \d+ золота на счет клана/.test(line)) {
gold = extractGoldAmount(line, /(\d+) золота/, true);
newline = makeColoredLine(line, gold, "red");
}
// Передача золота игроку
else if (/Передано \d+ (?:Золото|золота)\s+для/.test(line)) {
gold = extractGoldWithCommission(
line,
/(\d+) (?:Золото|золота)/,
/комиссия (\d+)/,
true
);
newline = makeColoredLine(line, gold, "red");
}
// Покупки
else if (
/Получен (?:элемент|предмет).+?за \d+ (?:золота|Золото)|Куплен|Куплена? \d+ часть артефакта/.test(
line
)
) {
gold = extractGoldAmount(line, /за (\d+) (?:золота|Золото)/, true);
newline = makeColoredLine(line, gold, "red");
}
// Продажи частей артефакта
else if (/Продано \d+ \(\d+ -> \d+\) частей артефакта/.test(line)) {
gold = extractGoldWithCommission(
line,
/за (\d+) золота/,
/комиссия: (\d+)/
);
newline = makeColoredLine(line, "+" + gold, "green");
}
// Продажи элементов
else if (/Продан "[^"]+"(?: \d+ шт\.)? за \d+ золота/.test(line)) {
gold = extractGoldWithCommission(
line,
/за (\d+) золота/,
/комиссия: (\d+)/
);
newline = makeColoredLine(line, "+" + gold, "green");
}
// Возвраты с возвратом золота
else if (/Неиспользовано|^Вернул/.test(line) && !/c ремонта/.test(line)) {
gold = extractGoldAmount(line, /(?:золота|Возврат золота): (\d+)/);
newline = makeColoredLine(line, "+" + gold, "green");
}
// Операции без влияния на баланс
else if (
/Забран предмет|Получен предмет(?!.+за \d+)|Передан предмет для|Возвращен предмет|Возвращено автоматически|Вернул c ремонта|Игрок (?:освобожден|помещен|разблокирован|заблокирован)/.test(
line
)
) {
gold = 0;
newline = line;
}
// Штрафы игрока
else if (/Игрок оштрафован/.test(line)) {
gold = extractGoldAmount(line, /на (\d+) золота/, true);
newline = makeColoredLine(line, gold, "red");
}
// Остальные покупки и траты
else if (/Оплачено \d+|Куплен|Внесено/.test(line)) {
gold = extractGoldAmount(line, /(\d+) золота/, true);
newline = makeColoredLine(line, gold, "red");
}
} catch (error) {}
return { processedLine: newline, goldAmount: gold };
}
// Page Management Functions
function getTotalPages(playerId, callback) {
let callbackCalled = false;
const safeCallback = (pages) => {
if (!callbackCalled) {
callbackCalled = true;
callback(pages);
}
};
const xhr = createXMLHttpRequest();
try {
xhr.open(
"GET",
`${url}pl_transfers.php?id=${playerId}&page=999999`,
true
);
setRequestHeaders(xhr);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
const responseDiv = document.createElement("div");
responseDiv.innerHTML = xhr.responseText;
const pagination = responseDiv.querySelector(".hwm_pagination");
if (pagination) {
const activeLink = pagination.querySelector("a.active");
if (activeLink) {
const totalPages = parseInt(activeLink.textContent.trim());
safeCallback(totalPages);
return;
}
const allLinks = pagination.querySelectorAll('a[href*="page="]');
let maxPageNumber = 0;
allLinks.forEach((link) => {
const pageMatch = link.href.match(/page=(\d+)/);
if (pageMatch) {
const pageNum = parseInt(pageMatch[1]);
maxPageNumber = Math.max(maxPageNumber, pageNum);
}
const linkText = parseInt(link.textContent.trim());
if (!isNaN(linkText)) {
maxPageNumber = Math.max(maxPageNumber, linkText);
}
});
const totalPages = maxPageNumber + 1;
safeCallback(totalPages);
} else {
safeCallback(1);
}
} else {
safeCallback(1);
}
}
};
xhr.send(null);
} catch (error) {
safeCallback(1);
}
}
// Core Functions
function makeRequest(requestUrl, callback, callbackData, firstPage) {
const xhr = createXMLHttpRequest();
try {
xhr.open("GET", requestUrl, true);
setRequestHeaders(xhr);
xhr.onreadystatechange = function () {
callback(xhr, callbackData, firstPage);
};
xhr.send(null);
} catch (error) {
alert("HWM_TransferSearch: " + error);
}
}
function startSearch(playerId, rootElement, searchType) {
createStopButton();
const stopButton = $(ELEMENT_IDS.STOP);
if (stopButton && stopButton.value === "1") {
return;
}
if (stopButton) {
stopButton.value = "0";
}
searchBalance = 0;
const pageFrom = Math.max(
1,
Math.floor(getNumberFieldValue(INPUT_IDS.PAGE_FROM, 1))
);
let pageTo = getNumberFieldValue(INPUT_IDS.PAGE_TO, 0);
hideSearchInterface();
if (pageTo === 0) {
displaySearchStatus(
searchType,
getSearchString(searchType),
"?",
pageFrom
);
const statusContainer = $(ELEMENT_IDS.SEARCH_STATUS);
statusContainer.innerHTML +=
"<br><i>Определяем общее количество страниц...</i>";
getTotalPages(playerId, function (totalPages) {
pageTo = totalPages;
continueSearch(playerId, rootElement, searchType, pageFrom, pageTo);
});
} else {
continueSearch(playerId, rootElement, searchType, pageFrom, pageTo);
}
}
function getSearchString(searchType) {
const inputMap = {
[SEARCH_TYPES.NICK]: INPUT_IDS.NICK,
[SEARCH_TYPES.FINE]: ELEMENT_IDS.CHECKBOX_LABEL,
[SEARCH_TYPES.ART]: INPUT_IDS.ART,
[SEARCH_TYPES.ANY]: INPUT_IDS.ALL,
};
const inputId = inputMap[searchType];
if (!inputId) return "";
const element = $(inputId);
if (!element) {
return "";
}
if (searchType === SEARCH_TYPES.FINE) {
return element.checked ? "true" : "false";
}
return element.value.trim();
}
function continueSearch(playerId, rootElement, searchType, pageFrom, pageTo) {
if (pageFrom > pageTo) {
alert("Начальная страница не может быть больше конечной!");
showSearchInterface();
return;
}
performSearch(playerId, searchType, rootElement, pageTo, pageFrom);
}
function performSearch(
playerId,
searchType,
rootElement,
totalPages,
firstPage
) {
let regex, searchString;
try {
({ regex, searchString } = createSearchRegex(searchType));
} catch (error) {
alert(error.message);
showSearchInterface();
return;
}
const playerNick = getPlayerNick(rootElement);
clearAndSetupResults(rootElement, playerNick, playerId);
searchBalance = 0;
const matchesElement = $("matches");
if (matchesElement) {
matchesElement.innerHTML = "0";
}
displaySearchStatus(searchType, searchString, totalPages, firstPage);
executePageSearch(
firstPage,
playerId,
regex,
totalPages,
rootElement,
searchType,
searchString,
firstPage,
null
);
}
function createSearchRegex(searchType) {
const searchString = getSearchString(searchType);
if (
!searchString &&
searchType !== SEARCH_TYPES.FINE &&
searchString !== "false"
) {
const errorMessages = {
[SEARCH_TYPES.NICK]: "Введите ник для поиска",
[SEARCH_TYPES.ART]: "Введите название артефакта для поиска",
[SEARCH_TYPES.ANY]: "Введите текст для поиска",
};
throw new Error(
errorMessages[searchType] || `Unknown search type: ${searchType}`
);
}
const regexPatterns = {
[SEARCH_TYPES.NICK]: `${DATE_TIME_PATTERN}: .*<b>${escapeRegexString(
searchString
)}</b></a>`,
[SEARCH_TYPES.FINE]: `${DATE_TIME_PATTERN}: <b>Игрок${
searchString === "true"
? " (?:оштрафован|освобожден|помещен|разблокирован|заблокирован)"
: " оштрафован"
}`,
[SEARCH_TYPES.ART]: `${DATE_TIME_PATTERN}: .*предмет [\"'][^\"']*${escapeRegexString(
searchString
)}[^\"']*[\"']`,
[SEARCH_TYPES.ANY]: `${DATE_TIME_PATTERN}: .*${escapeRegexString(
searchString
)}.*`,
};
const pattern = regexPatterns[searchType];
if (!pattern) {
throw new Error(`Unknown search type: ${searchType}`);
}
const flags = "i";
const regex = new RegExp(pattern, flags);
return { regex, searchString };
}
function executePageSearch(
currentPage,
playerId,
regex,
lastPage,
rootElement,
searchType,
searchString,
firstPage,
currentPageDate
) {
const stopButton = $(ELEMENT_IDS.STOP);
if (stopButton && stopButton.value !== "1" && currentPage <= lastPage) {
const searchArgs = {
pg: currentPage,
id: playerId,
reg: regex,
lastPg: lastPage,
elem: rootElement,
type: searchType,
search_str: searchString,
first_page: firstPage,
};
makeRequest(
`${url}pl_transfers.php?id=${playerId}&page=${currentPage - 1}`,
processPageResults,
searchArgs
);
} else {
displaySearchComplete(
searchType,
searchString,
firstPage,
currentPage - 1,
currentPageDate
);
}
}
function processPageResults(xhr, searchArgs) {
if (xhr.readyState === 4 && xhr.status === 200) {
hiddenDiv.innerHTML = xhr.responseText;
const transferContainer = hiddenDiv.getElementsByClassName(
SELECTORS.CONTAINER_HEADER
)[0].nextElementSibling;
const transferElement = transferContainer.getElementsByClassName(
SELECTORS.GLOBAL_HOVER
)[0];
if (!transferElement) return;
const transferText = transferElement.innerHTML;
const transfers = transferText.split("<br>");
let firstTimeOnPage = null;
const timeRegex = / (\d\d-\d\d-\d\d \d\d:\d\d):/;
for (let i = 0; i < transfers.length; i++) {
if (!firstTimeOnPage) {
const timeMatch = timeRegex.exec(transfers[i]);
if (timeMatch) firstTimeOnPage = timeMatch[1];
}
const originalText = extractOriginalText(transfers[i]);
if (searchArgs.reg.test(originalText)) {
const matchesElement = $("matches");
if (matchesElement) {
matchesElement.innerHTML = Number(matchesElement.innerHTML) + 1;
}
const result = processTransferBalance(transfers[i]);
const displayLine = result.processedLine;
const goldAmount = result.goldAmount;
searchBalance += goldAmount;
searchArgs.elem.innerHTML += displayLine;
searchArgs.elem.appendChild(document.createElement("br"));
}
}
if (firstTimeOnPage) {
const currDateElement = $("curr_date");
if (currDateElement) {
currDateElement.innerHTML = firstTimeOnPage;
}
}
updateSearchProgress(searchArgs.lastPg, searchArgs.first_page);
updateSearchBalance();
executePageSearch(
searchArgs.pg + 1,
searchArgs.id,
searchArgs.reg,
searchArgs.lastPg,
searchArgs.elem,
searchArgs.type,
searchArgs.search_str,
searchArgs.first_page,
firstTimeOnPage
);
}
}
// UI Helper Functions
function formatSearchTypeDisplay(searchType, searchString) {
const typeFormatters = {
[SEARCH_TYPES.NICK]: () => {
return `по нику <a href="pl_info.php?nick=${searchString}" style="text-decoration: none;"><b>${searchString}</b></a>`;
},
[SEARCH_TYPES.FINE]: () =>
searchString === "true" ? "штрафы, блок, тюрьма" : "штрафы",
[SEARCH_TYPES.ART]: () => `по артефакту "${searchString}"`,
[SEARCH_TYPES.ANY]: () => `по подстроке "${searchString}"`,
};
return typeFormatters[searchType]
? typeFormatters[searchType]()
: searchType;
}
function displaySearchStatus(
searchType,
searchString,
totalPages,
firstPage
) {
const formattedType = formatSearchTypeDisplay(searchType, searchString);
const oldStatus = $(ELEMENT_IDS.SEARCH_STATUS);
if (oldStatus) {
oldStatus.remove();
}
const statusContainer = document.createElement("div");
statusContainer.id = ELEMENT_IDS.SEARCH_STATUS;
statusContainer.style.textAlign = "center";
statusContainer.innerHTML = `
Идёт поиск ${formattedType}...
(<a href="javascript: void(0);" id="cancel" onclick="stopSearch();">стоп</a>)
<br />
Просмотрено <text id="viewed">0</text> страничек из ${
totalPages - firstPage + 1
}
(с ${firstPage} по ${totalPages}): <text id="percent">0</text>%
<br />
Дата последней операции на текущей странице: <text id="curr_date"></text>
<br />
Найдено <text id="matches">0</text> записей. Баланс: <text id="current_balance">0</text>
`;
rootElement.appendChild(statusContainer);
rootElement.appendChild(document.createElement("br"));
}
function displaySearchComplete(
searchType,
searchString,
firstPage,
lastPage,
currentPageDate
) {
const matches = $("matches").innerHTML;
const formattedType = formatSearchTypeDisplay(searchType, searchString);
const dateInfo = currentPageDate
? `<br/>Дата последней операции на странице ${lastPage}: ${currentPageDate}`
: "";
const formattedBalance = searchBalance.toLocaleString("en-US");
const balanceColor = searchBalance < 0 ? "red" : "green";
const balanceSign = searchBalance > 0 ? "+" : "";
$(ELEMENT_IDS.SEARCH_STATUS).innerHTML = `
Поиск ${formattedType} закончен!<br>
Найдено ${matches} записей на страницах ${firstPage}-${lastPage}:${dateInfo}
<br><br><b style='padding:20px'>Баланс найденных операций:
<span style='color:${balanceColor}'>${balanceSign}${formattedBalance}</span></b>
`;
}
function updateSearchProgress(totalPages, firstPage) {
const viewedElement = $("viewed");
const percentElement = $("percent");
if (viewedElement && percentElement) {
viewedElement.innerHTML = Number(viewedElement.innerHTML) + 1;
percentElement.innerHTML = Math.round(
(viewedElement.innerHTML * 100) / (totalPages - firstPage + 1)
);
}
}
function updateSearchBalance() {
const balanceElement = $("current_balance");
if (balanceElement) {
const formattedBalance = searchBalance.toLocaleString("en-US");
const balanceColor = searchBalance < 0 ? "red" : "green";
const balanceSign = searchBalance > 0 ? "+" : "";
balanceElement.innerHTML = `<span style='color:${balanceColor}'>${balanceSign}${formattedBalance}</span>`;
}
}
// UI Creation Functions
function createSearchInterface(rootElement) {
insertAfter(
rootElement.getElementsByTagName("center")[0].firstChild,
document.createElement("br")
);
const searchToggle = document.createElement("text");
searchToggle.id = ELEMENT_IDS.SEARCH_STATUS;
searchToggle.innerHTML = ` (<a id="${ELEMENT_IDS.SHOW_BLOCK}" href="javascript: void(0);">Поиск по протоколу</a>)`;
rootElement.getElementsByTagName("center")[0].appendChild(searchToggle);
const searchContainer = createSearchForm();
rootElement.getElementsByTagName("center")[0].appendChild(searchContainer);
}
function createSearchForm() {
const container = document.createElement("div");
container.id = ELEMENT_IDS.SEARCH_DIV;
container.style.display = "none";
container.innerHTML = `
<table>
<tr>
<td>Поиск по нику:</td>
<td><input type="text" id="${INPUT_IDS.NICK}" form="form_nick" /></td>
<td>
<form action="" style="padding:0;margin:0;border:0;" id="form_nick" onSubmit="return false;">
<input type="submit" id="TSearchByNick" value="Поиск" />
</form>
</td>
</tr>
<tr>
<td>Поиск штрафов:</td>
<td title="Блок/Штраф/Тюрьма">
<input type="checkbox" id="${ELEMENT_IDS.CHECKBOX_LABEL}" /> <label for="${ELEMENT_IDS.CHECKBOX_LABEL}">Блок/Штраф/Тюрьма</label>
</td>
<td><input type="submit" id="TSearchByFine" value="Поиск" /></td>
</tr>
<tr>
<td>Поиск по артефакту:</td>
<td><input type="text" id="${INPUT_IDS.ART}" form="form_art" /></td>
<td>
<form action="" style="padding:0;margin:0;border:0;" id="form_art" onSubmit="return false;">
<input type="submit" id="TSearchByArt" value="Поиск" />
</form>
</td>
</tr>
<tr>
<td>Общий Поиск:</td>
<td><input type="text" id="${INPUT_IDS.ALL}" form="form_any" /></td>
<td>
<form action="" style="padding:0;margin:0;border:0;" id="form_any" onSubmit="return false;">
<input type="submit" id="TSearchAny" value="Поиск" />
</form>
</td>
</tr>
<tr>
<td>с страницы</td>
<td title="Начать поиск с указанной страницы">
<input type="text" id="${INPUT_IDS.PAGE_FROM}" value="1"/>
</td>
<td> </td>
</tr>
<tr>
<td>по страницу</td>
<td title="Закончить поиск на указанной странице (0 = до конца)">
<input type="text" id="${INPUT_IDS.PAGE_TO}" value="0" placeholder="0 = до конца"/>
</td>
<td>
<button type="button" id="TSearch_get_total_pages" title="Определить общее количество страниц">
Узнать всего
</button>
</td>
</tr>
</table>
`;
return container;
}
function setupEventListeners(rootElement) {
if (rootElement._listenersAdded) {
return;
}
const eventHandlers = {
[ELEMENT_IDS.SHOW_BLOCK]: toggleSearchInterface,
TSearchByNick: () =>
startSearch(playerId, rootElement, SEARCH_TYPES.NICK),
TSearchByFine: () =>
startSearch(playerId, rootElement, SEARCH_TYPES.FINE),
TSearchByArt: () => startSearch(playerId, rootElement, SEARCH_TYPES.ART),
TSearchAny: () => startSearch(playerId, rootElement, SEARCH_TYPES.ANY),
TSearch_get_total_pages: () => handleGetTotalPages(),
};
Object.entries(eventHandlers).forEach(([elementId, handler]) => {
addClickHandler(elementId, handler);
});
rootElement._listenersAdded = true;
}
function handleGetTotalPages() {
const button = $("TSearch_get_total_pages");
const pageToField = $(INPUT_IDS.PAGE_TO);
if (button.disabled) return;
if (handleGetTotalPages.isRunning) {
return;
}
handleGetTotalPages.isRunning = true;
button.textContent = "Загрузка...";
button.disabled = true;
getTotalPages(playerId, function (totalPages) {
pageToField.value = totalPages;
button.textContent = "Узнать всего";
button.disabled = false;
handleGetTotalPages.isRunning = false;
});
}
// Utility Functions
function findRootElement() {
return document.getElementsByClassName(SELECTORS.CONTAINER_HEADER)[0]
.nextElementSibling;
}
function getPlayerNick(rootElement) {
return rootElement.previousSibling.getElementsByTagName("a")[0].innerHTML;
}
function clearAndSetupResults(rootElement, playerNick, playerId) {
const headerElement = rootElement.getElementsByClassName(
SELECTORS.GLOBAL_HOVER
)[0];
headerElement.innerHTML = "";
const titleContainer = document.createElement("div");
titleContainer.style.textAlign = "center";
titleContainer.innerHTML = "Поиск по протоколу передач игрока ";
const playerLink = document.createElement("a");
playerLink.href = `pl_info.php?id=${playerId}`;
playerLink.style.textDecoration = "none";
playerLink.innerHTML = playerNick;
titleContainer.appendChild(playerLink);
headerElement.appendChild(titleContainer);
headerElement.appendChild(document.createElement("br"));
}
function createStopButton() {
let stopButton = $(ELEMENT_IDS.STOP);
if (!stopButton) {
stopButton = document.createElement("input");
stopButton.type = "hidden";
stopButton.value = "0";
stopButton.id = ELEMENT_IDS.STOP;
document.getElementsByTagName("body")[0].appendChild(stopButton);
}
return stopButton;
}
function hideSearchInterface() {
$(ELEMENT_IDS.SEARCH_DIV).style.display = "none";
$(ELEMENT_IDS.SEARCH_STATUS).style.display = "none";
}
function showSearchInterface() {
$(ELEMENT_IDS.SEARCH_DIV).style.display = "block";
$(ELEMENT_IDS.SEARCH_STATUS).style.display = "block";
}
function createHiddenDiv() {
const div = document.createElement("div");
div.style.display = "none";
div.id = "hwm_transfer_search_hidden";
document.body.appendChild(div);
return div;
}
function escapeRegexString(str) {
return str
.replace(/\\/g, "\\\\")
.replace(/\[/g, "\\[")
.replace(/\]/g, "\\]")
.replace(/\(/g, "\\(")
.replace(/\)/g, "\\)")
.replace(/\./g, "\\.")
.replace(/\+/g, "\\+")
.replace(/\*/g, "\\*")
.replace(/\?/g, "\\?")
.replace(/\$/g, "\\$")
.replace(/\|/g, "\\|");
}
function toggleSearchInterface() {
const searchDiv = $(ELEMENT_IDS.SEARCH_DIV);
searchDiv.style.display =
searchDiv.style.display === "none" ? "block" : "none";
}
function insertAfter(referenceNode, newNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
function addClickHandler(elementId, handler) {
const element = $(elementId);
if (element && handler) {
addEventHandler(element, "click", handler);
}
}
function addEventHandler(element, eventType, handler) {
if (element) {
if (element.addEventListener) {
element.addEventListener(eventType, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + eventType, handler);
} else {
element["on" + eventType] = handler;
}
}
}
function getPlayerId() {
const match = location.href.match(/\?(?:.*=.*&)*id=([0-9]*)(?:&.*=.*)*/);
return match[1];
}
function $(elementId) {
return document.getElementById(elementId);
}
function getNumberFieldValue(fieldId, defaultValue) {
const element = $(fieldId);
return element ? getValidNumber(element.value) : defaultValue || 0;
}
function getValidNumber(value) {
const num = Number(value);
const validNum = isNaN(num) ? 0 : num;
return validNum < 0 ? 0 : validNum;
}
function createXMLHttpRequest() {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else if (window.ActiveXObject) {
return new ActiveXObject("Microsoft.XMLHTTP");
} else {
alert("Can't create XMLHttpRequest!");
return null;
}
}
function setRequestHeaders(xhr) {
xhr.setRequestHeader("Content-type", "text/html; charset=windows-1251");
if (xhr.overrideMimeType) {
xhr.overrideMimeType("text/html; charset=windows-1251");
}
}
})();