// ==UserScript==
// @name HWM_auction_upd
// @author Мифист
// @namespace Мифист
// @version 2.1.6
// @description Обновленный рынок
// @match https://www.heroeswm.ru/auction.php*
// @match https://*.lordswm.com/auction.php*
// @run-at document-end
// @grant none
// @license MIT
// @noframes
// ==/UserScript==
(async function initModule(view) {
'use strict';
if (document.visibilityState === 'hidden') {
const callback = () => initModule(view);
document.addEventListener('visibilitychange', callback, { once: true });
return;
}
// ====================
const allArtsData = {
"drak_greaves1": "events/drak_bgreaves1",
"drak_greaves2": "events/drak_bgreaves2",
"drak_greaves3": "events/drak_bgreaves3",
"ed_barrel1": "events/&",
"ed_barrel2": "events/&",
"ed_barrel3": "events/&",
"mir_bow1": "events/&",
"mir_bow2": "events/&",
"mir_bow3": "events/&",
"smaska1": "events/&",
"smaska2": "events/&",
"smaska3": "events/&",
"stalker_iring1": "events/&",
"stalker_iring2": "events/&",
"stalker_iring3": "events/&",
"wanderer_boot1": "events/&",
"wanderer_boot2": "events/&",
"wanderer_boot3": "events/&",
"10scroll": "&",
"12hron": "other/&",
"13coin": "&",
"16amul": "other/&",
"17bring": "other/&",
"2year_amul_lords": "&",
"3year_amul": "&",
"3year_art": "3rd",
"4year_klever": "&",
"5years_star": "5year_star",
"6ring": "&",
"7ka": "&",
"8amul_inf": "8amul",
"9amu_let": "other/9amulet",
"a_dagger1": "events/&",
"a_dagger2": "events/&",
"a_mallet": "auc_1lot",
"adv_armor1": "events/&",
"adv_armor2": "events/&",
"adv_boot1": "events/&",
"adv_boot2": "events/&",
"adv_clk1": "events/&",
"adv_clk2": "events/&",
"adv_fring1": "events/&",
"adv_fring2": "events/&",
"adv_hm1": "events/&",
"adv_hm2": "events/&",
"adv_longbow1": "events/&",
"adv_longbow2": "events/&",
"adv_neck1": "events/&",
"adv_neck2": "events/&",
"adv_saber1": "events/&",
"adv_saber2": "events/&",
"adv_shild1": "events/&",
"adv_shild2": "events/&",
"adv_sumk1": "events/&",
"adv_sumk2": "events/&",
"amf_body": "bwar/&",
"amf_boot": "bwar/&",
"amf_cl": "bwar/&",
"amf_helm": "bwar/&",
"amf_scroll": "bwar/&",
"amf_weap": "bwar/&",
"amulet19": "nwamulet19",
"amulet_of_luck": "lucknecklace",
"ankh1": "events/&",
"ankh2": "events/&",
"anomal_ring1": "events/&",
"anomal_ring2": "events/&",
"anomal_ring3": "events/&",
"antiair_cape": "&",
"antifire_cape": "&",
"antimagic_cape": "&",
"arm_armor1": "events/&",
"arm_armor2": "events/&",
"arm_armor3": "events/&",
"arm_bts1": "events/&",
"arm_bts2": "events/&",
"arm_bts3": "events/&",
"arm_cap1": "events/&",
"arm_cap2": "events/&",
"arm_cap3": "events/&",
"arm_clk1": "events/&",
"arm_clk2": "events/&",
"arm_clk3": "events/&",
"arm_r1": "events/&",
"arm_r2": "events/&",
"arm_r3": "events/&",
"arm_sekstant1": "events/&",
"arm_sekstant2": "events/&",
"arm_sekstant3": "events/&",
"armor15": "&",
"armor17": "anwarmor17",
"bafamulet15": "&",
"bal_cube": "events/&",
"barb_armor": "&",
"barb_boots": "&",
"barb_club": "&",
"barb_helm": "&",
"barb_shield": "&",
"battlem_cape": "events/&",
"bear_statue": "events/medved",
"bfly": "gifts/&",
"blackring": "other/&",
"blacksword": "&",
"blacksword1": "blacksword",
"bludgeon": "&",
"boots13": "&",
"boots15": "&",
"boots17": "bzbboots17",
"boots2": "&",
"bow14": "&",
"bow17": "bbobow17",
"bravery_medal": "braverymedal",
"bril_pendant": "gifts/&",
"bril_ring": "gifts/&",
"bring14": "&",
"broad_sword": "broadsword",
"brush": "&",
"brush_2011y": "brush",
"bshield1": "event/&",
"bshield2": "event/&",
"bshield3": "event/&",
"buben1": "events/&",
"buben2": "events/&",
"buben3": "events/&",
"bunt_medal1": "bunt_medal1f",
"bunt_medal2": "&",
"bunt_medal3": "bunt_medal3f",
"bwar1": "bwar/bmedal1",
"bwar2": "bwar/bmedal2",
"bwar3": "bwar/bmedal3",
"bwar4": "bwar/bmedal4",
"bwar5": "bwar/bmedal5",
"bwar6": "bwar/bmedal6",
"bwar7": "bwar/bmedal7",
"bwar_splo": "bwar/bmedala1",
"bwar_stoj": "bwar/bmedalb1",
"bwar_takt": "bwar/bmedalc1",
"castle_orden": "events/&",
"cat_statue": "events/e_cat",
"centaurbow": "&",
"chain_coif": "chaincoif",
"chains1": "events/&",
"chains2": "events/&",
"chains3": "events/&",
"ciras": "&",
"circ_ring": "&",
"cloack17": "clscloack17",
"cloackwz15": "&",
"clover_amul": "&",
"cold_shieldn": "&",
"cold_sword2014": "&",
"coldamul": "&",
"coldring_n": "coldring",
"commander_ring": "events/&",
"compass": "other/&",
"composite_bow": "&",
"crystal": "events/&",
"cubed": "events/&",
"cubeg": "events/&",
"cubes": "events/&",
"d_spray": "gifts/&",
"dagger": "&",
"dagger16": "&",
"dagger20": "&",
"dagger_dex": "&",
"dagger_myf": "&",
"dark_amul": "events/&",
"dark_armor": "events/&",
"dark_axe": "events/&",
"dark_boots": "events/&",
"dark_bow": "events/&",
"dark_cloak": "events/&",
"dark_dagger": "events/&",
"dark_helmet": "events/&",
"dark_ring": "events/&",
"dark_shield": "events/&",
"darkelfboots": "&",
"darkelfciras": "&",
"darkelfcloack": "&",
"darkelfkaska": "&",
"darkelfpendant": "&",
"darkelfstaff": "&",
"darkring": "&",
"def_sword": "&",
"defender_dagger": "gifts/&",
"defender_shield": "protectshield",
"dem_amulet": "&",
"dem_armor": "&",
"dem_axe": "&",
"dem_bootshields": "&",
"dem_dmech": "dmech",
"dem_dtopor": "dtopor",
"dem_helmet": "&",
"dem_kosa": "kosa",
"dem_shield": "&",
"demwar1": "&",
"demwar2": "&",
"demwar3": "&",
"demwar4": "&",
"demwar5": "&",
"demwar6": "&",
"dering": "event/&",
"dog_statue": "events/e_dog",
"doubt_ring": "necroring",
"dragon_crown": "other/&",
"dragon_shield": "&",
"dragonstone": "events/&",
"drak_armor1": "events/&",
"drak_armor2": "events/&",
"drak_armor3": "events/&",
"drak_crown1": "events/&",
"drak_crown2": "events/&",
"drak_crown3": "events/&",
"dring12": "rings/&",
"dring15": "rings/&",
"dring18": "rings/&",
"dring21": "rings/&",
"dring5": "rings/&",
"dring9": "rings/&",
"druid_amulet": "kwar/dd_amulet",
"druid_armor": "kwar/dd_robe",
"druid_boots": "kwar/dd_boots",
"druid_cloack": "kwar/dd_cloack",
"druid_staff": "kwar/dd_staff",
"dubina": "&",
"dudka": "event/&",
"dun_amul1": "events/&",
"dun_amul2": "events/&",
"dun_amul3": "events/&",
"dun_armor1": "events/&",
"dun_armor2": "events/&",
"dun_armor3": "events/&",
"dun_boots1": "events/&",
"dun_boots2": "events/&",
"dun_boots3": "events/&",
"dun_bow1": "events/&",
"dun_bow2": "events/&",
"dun_bow3": "events/&",
"dun_cloak1": "events/&",
"dun_cloak2": "events/&",
"dun_cloak3": "events/&",
"dun_dagger1": "events/&",
"dun_dagger2": "events/&",
"dun_dagger3": "events/&",
"dun_ring1": "events/&",
"dun_ring2": "events/&",
"dun_ring3": "events/&",
"dun_shield1": "events/&",
"dun_shield2": "events/&",
"dun_shield3": "events/&",
"dun_sword1": "events/&",
"dun_sword2": "events/&",
"dun_sword3": "events/&",
"dung_axe1": "events/&",
"dung_axe2": "events/&",
"dung_axe3": "events/&",
"dung_glefa1": "events/&",
"dung_glefa2": "events/&",
"dung_glefa3": "events/&",
"e_shield1": "events/&",
"e_shield2": "events/&",
"ed_armr1": "events/&",
"ed_armr2": "events/&",
"ed_armr3": "events/&",
"ed_bsword1": "events/&",
"ed_bsword2": "events/&",
"ed_bsword3": "events/&",
"ed_elfbow1": "events/&",
"ed_elfbow2": "events/&",
"ed_elfbow3": "events/&",
"ed_mbook1": "events/&",
"ed_mbook2": "events/&",
"ed_mbook3": "events/&",
"ed_pendant1": "events/&",
"ed_pendant2": "events/&",
"ed_pendant3": "events/&",
"ed_ring1": "events/&",
"ed_ring2": "events/&",
"ed_ring3": "events/&",
"ed_svboots1": "events/&",
"ed_svboots2": "events/&",
"ed_svboots3": "events/&",
"eddem_ring1": "events/&",
"eddem_ring2": "events/&",
"eddem_ring3": "events/&",
"eg_order1": "events/&",
"eg_order2": "events/&",
"eg_order3": "events/&",
"elfamulet": "&",
"elfboots": "&",
"elfbow": "&",
"elfdagger": "event/&",
"elfshirt": "&",
"elfwar1": "&",
"elfwar2": "&",
"elfwar3": "&",
"elfwar4": "&",
"elfwar5": "&",
"elfwar6": "&",
"energy_scroll": "&",
"eye1": "events/&",
"eye2": "events/&",
"eye3": "events/&",
"fear_amulk": "events/&",
"fear_bonearmour": "events/&",
"fear_boots": "events/&",
"fear_cloack": "events/&",
"fear_scythe": "events/&",
"ffstaff15": "&",
"finecl": "&",
"firehammer": "events/&",
"firsword15": "&",
"flower_heart": "gifts/&",
"flowers1": "gifts/_&",
"flowers2": "gifts/_&",
"flowers3": "gifts/_&",
"flowers4": "gifts/buk2",
"flowers5": "gifts/buk1",
"flyaga": "events/&",
"forest_armor": "events/&",
"forest_blade": "events/&",
"forest_bolt": "events/&",
"forest_boots": "events/&",
"forest_bow": "events/&",
"forest_crossbow": "events/&",
"forest_dagger": "events/&",
"forest_helm": "events/&",
"forest_knives": "events/&",
"full_plate": "&",
"gargoshield": "events/&",
"gdubina": "&",
"gm_3arrows": "gm/&",
"gm_abow": "gm/&",
"gm_amul": "gm/&",
"gm_arm": "gm/&",
"gm_defence": "gm/&",
"gm_hat": "gm/&",
"gm_kastet": "gm/&",
"gm_protect": "gm/&",
"gm_rring": "gm/&",
"gm_spdb": "gm/&",
"gm_sring": "gm/&",
"gm_sword": "gm/&",
"gmage_armor": "kwar/bm_robe",
"gmage_boots": "kwar/bm_boots",
"gmage_cloack": "kwar/bm_cloack",
"gmage_crown": "kwar/bm_crown",
"gmage_scroll": "kwar/bm_scroll",
"gmage_staff": "kwar/bm_staff",
"gnome_hammer": "onehandaxe",
"gnomearmor": "gnomewar/armor1",
"gnomeboots": "gnomewar/boots1",
"gnomehammer": "gnomewar/hammer1",
"gnomehelmet": "gnomewar/helmet1",
"gnomem_amulet": "gnomewar/amulet2",
"gnomem_armor": "gnomewar/armor2",
"gnomem_boots": "gnomewar/gw_boots2",
"gnomem_hammer": "gnomewar/hammer2",
"gnomem_helmet": "gnomewar/helmet2",
"gnomem_shield": "gnomewar/shield2",
"gnomeshield": "gnomewar/shield1",
"gnomewar1": "gnomewar/medal1",
"gnomewar2": "gnomewar/medal2",
"gnomewar3": "gnomewar/medal3",
"gnomewar4": "gnomewar/medal4",
"gnomewar5": "gnomewar/medal5",
"gnomewar6": "gnomewar/medal6",
"gnomewar7": "gnomewar/medal7",
"goblin_bow": "&",
"goldciras": "gifts/&",
"gring": "events/&",
"gringd": "events/&",
"half_heart_m": "gifts/&",
"half_heart_w": "gifts/&",
"hauberk": "chainarmor",
"heaven_amlt": "events/&",
"heaven_armr": "events/&",
"heaven_bow": "events/&",
"heaven_bts": "events/&",
"heaven_clk": "events/&",
"heaven_dagger": "events/&",
"heaven_helm": "events/&",
"heaven_rn": "events/&",
"heaven_shield": "events/&",
"heaven_staff": "events/&",
"helmet17": "hwmhelmet17",
"hm1": "events/&",
"hm2": "events/&",
"hopesh1": "events/&",
"hopesh2": "events/&",
"hunter_amulet1": "&",
"hunter_armor1": "&",
"hunter_arrows1": "&",
"hunter_boots": "hunterboots",
"hunter_boots1": "&",
"hunter_boots2": "&",
"hunter_boots3": "&",
"hunter_bow1": "&",
"hunter_bow2": "&",
"hunter_gloves1": "&",
"hunter_hat1": "&",
"hunter_helm": "&",
"hunter_jacket1": "&",
"hunter_mask1": "&",
"hunter_pendant1": "&",
"hunter_ring1": "&",
"hunter_ring2": "&",
"hunter_roga1": "&",
"hunter_shield1": "&",
"hunter_sword1": "&",
"hunterdagger": "&",
"hunterdsword": "&",
"huntershield2": "&",
"huntersword2": "&",
"i_ring": "&",
"icebow1": "events/&",
"icebow2": "events/&",
"icebow3": "events/&",
"icecr1": "events/&",
"icecr2": "events/&",
"icecr3": "events/&",
"icesphere1": "events/&",
"icesphere2": "events/&",
"icesphere3": "events/&",
"imp_amul": "events/&",
"imp_armor": "events/&",
"imp_boots": "events/&",
"imp_cloak": "events/&",
"imp_crossbow": "events/&",
"imp_dagger": "events/&",
"imp_helmet": "events/&",
"imp_ring": "events/&",
"imp_shield": "events/&",
"imp_sword": "events/&",
"inq_body": "bwar/&",
"inq_boot": "bwar/&",
"inq_cl": "bwar/&",
"inq_helm": "bwar/&",
"inq_ring1": "events/&",
"inq_ring2": "events/&",
"inq_weap": "bwar/&",
"kn_body": "bwar/&",
"kn_helm": "bwar/&",
"kn_shield": "bwar/&",
"kn_weap": "bwar/&",
"kniga": "events/&",
"knightarmor": "kwar/kk_armor",
"knightboots": "kwar/kk_boots",
"knighthelmet": "kwar/kk_helmet",
"knightshield": "kwar/kk_shield",
"knightsword": "kwar/kk_sword",
"knowledge_hat": "knowlengehat",
"koltsou": "&",
"kopie": "&",
"krest1": "events/&",
"krest2": "events/&",
"krest3": "events/&",
"kwar1": "kwar/kmedal1",
"kwar2": "kwar/kmedal2",
"kwar3": "kwar/kmedal3",
"kwar4": "kwar/kmedal4",
"kwar5": "kwar/kmedal5",
"kwar6": "kwar/kmedal6",
"kwar7": "kwar/kmedal7",
"kwar_splo": "kwar/medala",
"kwar_stoj": "kwar/medalb",
"kwar_takt": "kwar/medalc",
"kznamya1": "events/&",
"kznamya2": "events/&",
"large_shield": "&",
"lbow": "&",
"leather_helm": "leatherhelmet",
"leather_shiled": "leathershield",
"leatherboots": "&",
"leatherhat": "&",
"leatherplate": "&",
"les_cl": "events/&",
"lizard_helm": "&",
"long_bow": "&",
"lotus1": "events/&",
"lotus2": "events/&",
"lotus3": "events/&",
"m_amul1": "events/&",
"m_amul2": "events/&",
"m_amul3": "events/&",
"m_armor1": "events/&",
"m_armor2": "events/&",
"m_armor3": "events/&",
"mage_armor": "&",
"mage_boots": "war/&",
"mage_cape": "war/&",
"mage_hat": "war/&",
"mage_helm": "&",
"mage_robe": "war/&",
"mage_scroll": "war/&",
"mage_staff": "war/&",
"magewar1": "medals/&",
"magewar2": "medals/&",
"magewar3": "medals/&",
"magewar4": "medals/&",
"magewar5": "medals/&",
"magic_amulet": "&",
"magma_arb": "events/&",
"magma_armor": "events/&",
"magma_boots": "events/&",
"magma_clc": "events/&",
"magma_dagger": "events/&",
"magma_helm": "events/&",
"magma_lshield": "events/&",
"magma_pend": "events/&",
"magma_rd": "events/&",
"magma_swrd": "events/&",
"magneticarmor": "events/&",
"magring13": "&",
"mamulet19": "megmamulet19",
"marmor17": "mammarmor17",
"mart8_flowers1": "_flower1",
"mart8_ring1": "_womenring1",
"mboots14": "&",
"mboots17": "macmboots17",
"mechanic_glasses1": "events/mechanics_glasses1",
"mechanic_glasses2": "events/mechanics_glasses2",
"mechanic_glasses3": "events/mechanics_glasses3",
"merc_armor": "&",
"merc_boots": "&",
"merc_dagger": "&",
"merc_sword": "&",
"mgear": "events/mgear1",
"mh_sword1": "events/&",
"mh_sword2": "events/&",
"mh_sword3": "events/&",
"mhelmet17": "miqmhelmet17",
"mhelmetzh13": "&",
"mhelmv1": "events/&",
"mhelmv2": "events/&",
"mhelmv3": "events/&",
"mif_hboots": "&",
"mif_hhelmet": "&",
"mif_lboots": "&",
"mif_lhelmet": "&",
"mif_light": "&",
"mif_staff": "&",
"mif_sword": "&",
"miff_plate": "&",
"mir_am1": "events/&",
"mir_am2": "events/&",
"mir_am3": "events/&",
"mir_armor1": "events/&",
"mir_armor2": "events/&",
"mir_armor3": "events/&",
"mir_boots1": "events/&",
"mir_boots2": "events/&",
"mir_boots3": "events/&",
"mir_cl1": "events/&",
"mir_cl2": "events/&",
"mir_cl3": "events/&",
"mir_helmt1": "events/&",
"mir_helmt2": "events/&",
"mir_helmt3": "events/&",
"mir_shld1": "events/&",
"mir_shld2": "events/&",
"mir_shld3": "events/&",
"mirror": "events/&",
"mm_staff": "&",
"mm_sword": "&",
"mmmring16": "&",
"mmzamulet13": "&",
"mmzamulet16": "&",
"molot_tan": "&",
"mring19": "meqmring19",
"msphere": "events/&",
"mstaff10": "&",
"mstaff13": "&",
"mstaff8": "&",
"mtcloak1": "other/&",
"mtcloak2": "other/&",
"mtcloak3": "other/&",
"myhelmet15": "&",
"n_amul": "nset/&",
"n_armor": "nset/&",
"n_boots": "nset/&",
"n_clk": "nset/&",
"n_helmet": "nset/&",
"n_ringa": "nset/&",
"n_ringd": "nset/&",
"n_shield": "nset/&",
"n_sword": "nset/&",
"necr_amulet": "&",
"necr_helm": "&",
"necr_robe": "necr_cloak",
"necr_staff": "&",
"necrohelm1": "&",
"necrohelm2": "&",
"necrohelm3": "&",
"necrwar1st": "&",
"necrwar2st": "&",
"necrwar3st": "&",
"necrwar4st": "&",
"necrwar5st": "&",
"nefrit1": "events/nefrit_1",
"nefrit2": "events/nefrit_2",
"nefrit3": "events/nefrit_3",
"neut_amulet": "sh/sh_amulet",
"neut_ring": "events/forest_ring",
"nv_body": "bwar/&",
"nv_boot": "bwar/&",
"nv_helm": "bwar/&",
"nv_shield": "bwar/&",
"nv_weap": "bwar/&",
"obereg": "events/&",
"ocean_boots1": "events/&",
"ocean_boots2": "events/&",
"ocean_boots3": "events/&",
"ocean_bw1": "events/&",
"ocean_bw2": "events/&",
"ocean_bw3": "events/&",
"ocean_cl1": "events/&",
"ocean_cl2": "events/&",
"ocean_cl3": "events/&",
"ocean_dgr1": "events/&",
"ocean_dgr2": "events/&",
"ocean_dgr3": "events/&",
"ocean_eye1": "events/&",
"ocean_eye2": "events/&",
"ocean_eye3": "events/&",
"ocean_hlm1": "events/&",
"ocean_hlm2": "events/&",
"ocean_hlm3": "events/&",
"ocean_m_shield1": "events/m_shield1",
"ocean_m_shield2": "events/m_shield2",
"ocean_m_shield3": "events/m_shield3",
"ocean_per1": "events/&",
"ocean_per2": "events/&",
"ocean_per3": "events/&",
"ocean_ring1": "events/&",
"ocean_ring2": "events/&",
"ocean_ring3": "events/&",
"ocean_sword1": "events/&",
"ocean_sword2": "events/&",
"ocean_sword3": "events/&",
"ogre_bum": "&",
"ogre_helm": "&",
"orc_axe": "&",
"orc_hat": "&",
"ord_dark": "events/order_dark",
"ord_light": "events/order_light",
"order_griffin": "events/&",
"order_manticore": "events/&",
"p_amulet1": "pirate_event/&",
"p_amulet2": "pirate_event/&",
"p_amulet3": "pirate_event/&",
"p_boots1": "pirate_event/&",
"p_boots2": "pirate_event/&",
"p_boots3": "pirate_event/&",
"p_cloak1": "pirate_event/&",
"p_cloak2": "pirate_event/&",
"p_cloak3": "pirate_event/&",
"p_compas1": "pirate_event/p_compass1",
"p_compas2": "pirate_event/p_compass2",
"p_compas3": "pirate_event/p_compass3",
"p_dag1": "events/&",
"p_dag2": "events/&",
"p_dag3": "events/&",
"p_pistol1": "pirate_event/&",
"p_pistol2": "pirate_event/&",
"p_pistol3": "pirate_event/&",
"p_sword1": "pirate_event/&",
"p_sword2": "pirate_event/&",
"p_sword3": "pirate_event/&",
"paladin_armor": "kwar/hc_armor",
"paladin_boots": "kwar/hc_boots",
"paladin_bow": "kwar/hc_crossbow",
"paladin_helmet": "kwar/hc_helmet",
"paladin_shield": "kwar/hc_shield",
"paladin_sword": "kwar/hc_sword",
"pegaskop": "event/&",
"pen": "&",
"pen_2011y_clan": "pen",
"pend_a1": "events/&",
"pend_a2": "events/&",
"pend_a3": "events/&",
"pika": "&",
"pir_armor1": "pirate_event/&",
"pir_armor2": "pirate_event/&",
"pir_armor3": "pirate_event/&",
"piratehat1": "pirate_event/&",
"piratehat2": "pirate_event/&",
"piratehat3": "pirate_event/&",
"piring1": "pirate_event/&",
"piring2": "pirate_event/&",
"piring3": "pirate_event/&",
"pit_sword1": "events/&",
"pit_sword2": "events/&",
"pn_ring1": "pirate_event/&",
"pn_ring2": "pirate_event/&",
"pn_ring3": "pirate_event/&",
"polk__helm1": "&",
"polk__helm2": "&",
"polk__helm3": "&",
"polk_armor1": "events/&",
"polk_armor2": "events/&",
"polk_armor3": "events/&",
"polk_sword1": "events/&",
"polk_sword2": "events/&",
"polk_sword3": "events/&",
"polkboots1": "events/&",
"polkboots2": "events/&",
"polkboots3": "events/&",
"potion01": "potions/zel0001",
"potion02": "potions/zel0002",
"potion03": "potions/zel0003",
"potion04": "potions/zel0004",
"potion05": "potions/zel0005",
"potion06": "potions/zel0006",
"potion07": "potions/zel0007",
"potion08": "potions/zel0008",
"pouch": "events/&",
"power_pendant": "&",
"power_sword": "&",
"powercape": "&",
"powerring": "&",
"protazan": "gifts/&",
"quest_pendant1": "other/&",
"r_bigsword": "ranger/&",
"r_bootsmb": "ranger/&",
"r_bow": "ranger/&",
"r_clck": "ranger/&",
"r_dagger": "ranger/&",
"r_goodscroll": "ranger/&",
"r_helmb": "ranger/&",
"r_m_amulet": "ranger/&",
"r_magicsring": "ranger/&",
"r_magy_staff": "ranger/&",
"r_warring": "ranger/&",
"r_warriorsamulet": "ranger/&",
"r_zarmor": "ranger/&",
"ramul1": "events/&",
"ramul2": "events/&",
"rarmor1": "events/&",
"rarmor2": "events/&",
"rashness_ring": "hastering",
"raxe1": "events/&",
"raxe2": "events/&",
"rboots1": "events/&",
"rboots2": "events/&",
"rbow1": "events/&",
"rbow2": "events/&",
"rcloak1": "events/&",
"rcloak2": "events/&",
"rdagger1": "events/&",
"rdagger2": "events/&",
"requital_sword": "requitalsword",
"rhelm1": "events/&",
"rhelm2": "events/&",
"ring19": "rarring19",
"ring2013": "snake_ring",
"ring_of_thief": "thief_ring",
"robewz15": "&",
"rog_demon": "&",
"rogring1": "events/&",
"rogring2": "events/&",
"roses": "gifts/&",
"round_shiled": "roundshield",
"rshield1": "events/&",
"rshield2": "events/&",
"rsword1": "events/&",
"rsword2": "events/&",
"ru_statue": "ruru9",
"runkam": "events/&",
"s_shield": "&",
"samul14": "samul141",
"samul17": "warsamul17",
"samul8": "samul81",
"sandglass": "events/&",
"sarmor13": "&",
"sarmor16": "brsarmor16",
"sarmor9": "&",
"sboots12": "&",
"sboots16": "nmsboots16",
"sboots9": "&",
"scloack16": "mascloack16",
"scloack8": "&",
"scoutcloack": "cloack",
"scroll18": "shhscroll18",
"sea_trident": "trident",
"sh_4arrows": "sh/&",
"sh_amulet2": "sh/&",
"sh_armor": "sh/&",
"sh_boots": "sh/&",
"sh_bow": "sh/&",
"sh_cloak": "sh/&",
"sh_helmet": "sh/&",
"sh_ring1": "sh/&",
"sh_ring2": "sh/&",
"sh_shield": "sh/&",
"sh_spear": "sh/&",
"sh_sword": "sh/&",
"sharik": "ny2014/&",
"shelm12": "&",
"shelm16": "umshelm16",
"shelm8": "&",
"shield13": "&",
"shield16": "&",
"shield19": "sioshield19",
"shield_14y": "14shield",
"shieldofforest": "events/&",
"shoe_of_initiative": "initboots",
"shortbow": "&",
"shpaga": "&",
"skill_book11": "other/skill_book",
"slayersword": "&",
"smamul14": "&",
"smamul17": "sekmamul17",
"smring10": "&",
"smring17": "masmring17",
"smstaff16": "ssmstaff16",
"sniperbow": "event/&",
"sor_staff": "&",
"soul_cape": "soulcape",
"sph1": "events/&",
"sph2": "events/&",
"sph3": "events/&",
"sring10": "&",
"sring17": "fgsring17",
"sring4": "&",
"sshield11": "&",
"sshield14": "zpsshield14",
"sshield17": "esshield17",
"sshield5": "&",
"ssword10": "&",
"ssword13": "&",
"ssword16": "szzsword16",
"ssword8": "&",
"staff": "&",
"staff18": "smmstaff18",
"staff_v1": "events/&",
"staff_v2": "events/&",
"staff_v3": "events/&",
"stalker_aml1": "events/&",
"stalker_aml2": "events/&",
"stalker_aml3": "events/&",
"stalker_armour1": "events/&",
"stalker_armour2": "events/&",
"stalker_armour3": "events/&",
"stalker_boot1": "events/&",
"stalker_boot2": "events/&",
"stalker_boot3": "events/&",
"stalker_cl1": "events/&",
"stalker_cl2": "events/&",
"stalker_cl3": "events/&",
"stalker_crsb1": "events/&",
"stalker_crsb2": "events/&",
"stalker_crsb3": "events/&",
"stalker_dagger1": "events/&",
"stalker_dagger2": "events/&",
"stalker_dagger3": "events/&",
"stalker_hlm1": "events/&",
"stalker_hlm2": "events/&",
"stalker_hlm3": "events/&",
"stalker_shid1": "events/&",
"stalker_shid2": "events/&",
"stalker_shid3": "events/&",
"stalkercl": "event/&",
"statue": "events/&",
"steel_blade": "steelsword",
"steel_boots": "&",
"steel_helmet": "&",
"student_armor": "quests/&",
"sumka": "events/&",
"sun_armor": "&",
"sun_boots": "&",
"sun_helm": "&",
"sun_ring": "&",
"sun_staff": "&",
"sunart1": "&",
"sunart2": "&",
"sunart3": "&",
"sunart4": "&",
"super_dagger": "&",
"surv_armorsu": "survarts/&",
"surv_axes": "survarts/&",
"surv_bootsurv": "survarts/&",
"surv_cloacksrv": "survarts/&",
"surv_crossbowsurv": "survarts/&",
"surv_daggermd": "survarts/&",
"surv_halberdzg": "survarts/&",
"surv_helmetpi": "survarts/&",
"surv_mamulka": "survarts/&",
"surv_marmoroz": "survarts/&",
"surv_mbootsbb": "survarts/&",
"surv_mcloacksv": "survarts/&",
"surv_mhelmetcv": "survarts/&",
"surv_mring1fd": "survarts/&",
"surv_mring2fpg": "survarts/&",
"surv_scrollcd": "survarts/&",
"surv_shieldvv": "survarts/&",
"surv_staffik": "survarts/&",
"surv_sword2sd": "survarts/&",
"surv_sword_surv": "survarts/&",
"surv_wamuletik": "survarts/&",
"surv_wring1my": "survarts/&",
"surv_wring2o": "survarts/&",
"sv_arb": "bwar/&",
"sv_body": "bwar/&",
"sv_boot": "bwar/&",
"sv_helm": "bwar/&",
"sv_shield": "bwar/&",
"sv_weap": "bwar/&",
"sword18": "smasword18",
"sword5": "&",
"tact1w1_wamulet": "tact/&",
"tact765_bow": "tact/&",
"tactaz_axe": "tact/&",
"tactcv1_armor": "tact/&",
"tactdff_shield": "tact/&",
"tacthapp_helmet": "tact/&",
"tactmag_staff": "tact/&",
"tactms1_mamulet": "tact/&",
"tactpow_cloack": "tact/&",
"tactsm0_dagger": "tact/&",
"tactspw_mring": "tact/&",
"tactwww_wring": "tact/&",
"tactzl4_boots": "tact/&",
"taskaxe": "event/&",
"testring": "&",
"thief_arb": "&",
"thief_cape": "&",
"thief_fastboots": "thief_boots",
"thief_goodarmor": "thief_armor",
"thief_ml_dagger": "thief_dagger",
"thief_msk": "thief_mask",
"thief_neckl": "thief_amulet",
"thief_paper": "&",
"thief_premiumring1": "medals/&",
"thief_premiumring2": "medals/&",
"thief_premiumring3": "medals/&",
"tj-shield1": "&",
"tj-shield2": "&",
"tj-shield3": "&",
"tj_helmet1": "&",
"tj_helmet2": "&",
"tj_helmet3": "&",
"tj_magam1": "events/&",
"tj_magam2": "events/&",
"tj_magam3": "events/&",
"tj_mtuf1": "events/&",
"tj_mtuf2": "events/&",
"tj_mtuf3": "events/&",
"tj_vboots1": "&",
"tj_vboots2": "&",
"tj_vboots3": "&",
"tjam1": "&",
"tjam2": "&",
"tjam3": "&",
"tjarmor1": "&",
"tjarmor2": "&",
"tjarmor3": "&",
"tl_medal1": "tiger_gold",
"tl_medal2": "tiger_silver",
"tl_medal3": "tiger_bronze",
"tm_amulet": "&",
"tm_arb": "&",
"tm_armor": "&",
"tm_boots": "&",
"tm_cape": "&",
"tm_knife": "&",
"tm_mring": "&",
"tm_msk": "tm_mask",
"tm_wring": "&",
"tmarmor1": "events/&",
"tmarmor2": "events/&",
"tmarmor3": "events/&",
"topor_drov": "events/&",
"topor_skelet": "&",
"torg_boots": "events/&",
"totem1": "events/&",
"totem2": "events/&",
"totem3": "events/&",
"trinitypendant": "other/rogue_pendant",
"trogloditkop": "event/&",
"ttring": "other/&",
"tunnel_kirka": "kirka",
"v-ring1": "&",
"v-ring2": "&",
"v-ring3": "&",
"v_1armor": "verb/&",
"vbolt1": "event/&",
"vbolt2": "event/&",
"vbolt3": "event/&",
"vbow1": "event/&",
"vbow2": "event/&",
"vbow3": "event/&",
"ve_helm": "verb/&",
"venok": "gifts/&",
"verb11_sword": "verb/&",
"verbboots": "verb/&",
"verve_ring": "eaglering",
"vmring1": "events/mring1",
"vmring2": "events/mring2",
"vmring3": "events/mring3",
"vrb_shild": "verb/&",
"vrdagger1": "events/&",
"vrdagger2": "events/&",
"vrdagger3": "events/&",
"vscroll-1": "events/vscroll1",
"vscroll-2": "events/vscroll2",
"vscroll-3": "events/vscroll3",
"vtjcloak1": "other/&",
"vtjcloak2": "other/&",
"vtjcloak3": "other/&",
"vtmaxe1": "events/&",
"vtmaxe2": "events/&",
"vtmaxe3": "events/&",
"vtmsword1": "events/&",
"vtmsword2": "events/&",
"vtmsword3": "events/&",
"wanderer_armor1": "events/&",
"wanderer_armor2": "events/&",
"wanderer_armor3": "events/&",
"wanderer_hat1": "events/&",
"wanderer_hat2": "events/&",
"wanderer_hat3": "events/&",
"warmor": "gifts/&",
"warring13": "&",
"warrior_pendant": "&",
"warriorring": "&",
"warthief_medal1": "medals/&",
"warthief_medal2": "medals/&",
"warthief_medal3": "medals/&",
"warthief_medal4": "medals/&",
"warthief_medal5": "medals/&",
"wboots": "gifts/&",
"welfarmor": "kwar/ew_armor",
"welfboots": "kwar/ew_bootshields",
"welfbow": "kwar/ew_bow",
"welfhelmet": "kwar/ew_helmet",
"welfshield": "kwar/ew_shield",
"welfsword": "kwar/ew_sword",
"whelmet": "gifts/&",
"wind_armor": "&",
"wind_boots": "&",
"wind_helm": "&",
"windsword": "event/&",
"wiz_boots": "&",
"wiz_cape": "&",
"wiz_robe": "mage_robes",
"wizard_cap": "magehat",
"wolfjacket": "&",
"wood_sword": "woodensword",
"wshield": "&",
"wwwring16": "&",
"wzzamulet13": "&",
"wzzamulet16": "&",
"xymhelmet15": "&",
"znak1": "events/znak0001",
"znak2": "events/znak0002",
"znak3": "events/znak0003",
"znak4": "events/znak0004",
"znak5": "events/znak0005",
"znak6": "events/znak0006",
"znak7": "events/znak0007",
"znak8": "events/znak0008",
"znak9": "events/znak0009",
"znamya1": "events/&",
"znamya2": "events/&",
"zub": "&",
"zxhelmet13": "&",
};
const allSetData = {
hunt_set: {
rus: "Охотника",
arts: [
"hunter_sword1",
"hunter_shield1",
"hunter_bow1",
"hunter_hat1",
"hunter_jacket1",
"hunter_boots1",
"hunter_gloves1",
"hunter_pendant1",
]
},
mhunt_set: {
rus: "Мастера-охотника",
arts: [
"hunterdsword",
"huntersword2",
"hunterdagger",
"huntershield2",
"hunter_arrows1",
"hunter_bow2",
"hunter_mask1",
"hunter_helm",
"hunter_roga1",
"hunter_armor1",
"hunter_boots2",
"hunter_boots3",
"hunter_ring1",
"hunter_ring2",
"hunter_amulet1",
]
},
ghunt_set: {
rus: "Великого охотника",
arts: [
"gm_sword",
"gm_kastet",
"gm_defence",
"gm_3arrows",
"gm_abow",
"gm_protect",
"gm_hat",
"gm_arm",
"gm_spdb",
"gm_sring",
"gm_rring",
"gm_amul",
]
},
bst_set: {
rus: "Зверобоя",
arts: [
"sh_sword",
"sh_spear",
"sh_shield",
"sh_4arrows",
"sh_bow",
"sh_cloak",
"sh_helmet",
"sh_armor",
"sh_boots",
"sh_ring1",
"sh_ring2",
"sh_amulet2",
]
},
vor: {
rus: "Вора",
arts: [
"thief_ml_dagger",
"thief_arb",
"thief_cape",
"thief_msk",
"thief_goodarmor",
"thief_fastboots",
"ring_of_thief",
"thief_neckl",
]
},
nal: {
rus: "Налётчика",
arts: [
"tm_knife",
"tm_arb",
"tm_cape",
"tm_msk",
"tm_armor",
"tm_boots",
"tm_mring",
"tm_wring",
"tm_amulet",
]
},
rang: {
rus: "Рейнджера",
arts: [
"r_bigsword",
"r_dagger",
"r_magy_staff",
"r_goodscroll",
"r_bow",
"r_clck",
"r_helmb",
"r_zarmor",
"r_bootsmb",
"r_magicsring",
"r_warring",
"r_warriorsamulet",
"r_m_amulet",
]
},
comm: {
rus: "Тактика",
arts: [
"tactmag_staff",
"tactaz_axe",
"tactsm0_dagger",
"tactdff_shield",
"tact765_bow",
"tactpow_cloack",
"tacthapp_helmet",
"tactcv1_armor",
"tactzl4_boots",
"tactspw_mring",
"tactwww_wring",
"tact1w1_wamulet",
"tactms1_mamulet",
]
},
rec: {
rus: "Вербовщика",
arts: [
"verb11_sword",
"vrb_shild",
"ve_helm",
"v_1armor",
"verbboots",
]
},
naemv: {
rus: "Наёмника-воина",
arts: [
"merc_sword",
"merc_dagger",
"merc_armor",
"merc_boots",
]
},
mil: {
rus: "Рыцаря-воина",
arts: [
"knightsword",
"knightshield",
"knighthelmet",
"knightarmor",
"knightboots",
]
},
pal: {
rus: "Паладина",
arts: [
"paladin_sword",
"paladin_shield",
"paladin_bow",
"paladin_helmet",
"paladin_armor",
"paladin_boots",
]
},
necrn: {
rus: "Некроманта-ученика",
arts: [
"necr_staff",
"necr_helm",
"necr_robe",
"necr_amulet",
]
},
mags: {
rus: "Мага-ученика",
arts: [
"mage_staff",
"mage_scroll",
"mage_cape",
"mage_hat",
"mage_robe",
"mage_boots",
]
},
velm: {
rus: "Великого мага",
arts: [
"gmage_staff",
"gmage_scroll",
"gmage_cloack",
"gmage_crown",
"gmage_armor",
"gmage_boots",
]
},
elfs: {
rus: "Эльфа-скаута",
arts: [
"elfbow",
"elfshirt",
"elfboots",
"elfamulet",
]
},
elfv: {
rus: "Эльфа-воина",
arts: [
"welfsword",
"welfshield",
"welfbow",
"welfhelmet",
"welfarmor",
"welfboots",
]
},
drd: {
rus: "Друида",
arts: [
"druid_staff",
"druid_cloack",
"druid_armor",
"druid_boots",
"druid_amulet",
]
},
varv: {
rus: "Варвара-воина",
arts: [
"barb_club",
"barb_shield",
"barb_helm",
"barb_armor",
"barb_boots",
]
},
slugt: {
rus: "Слуги тьмы",
arts: [
"darkelfstaff",
"darkelfcloack",
"darkelfkaska",
"darkelfciras",
"darkelfboots",
"darkelfpendant",
]
},
dems: {
rus: "Демона-воина",
arts: [
"dem_axe",
"dem_shield",
"dem_helmet",
"dem_armor",
"dem_bootshields",
"dem_amulet",
]
},
gnomv: {
rus: "Гнома-воина",
arts: [
"gnomehammer",
"gnomeshield",
"gnomehelmet",
"gnomearmor",
"gnomeboots",
]
},
gnomm: {
rus: "Гнома-мастера",
arts: [
"gnomem_hammer",
"gnomem_shield",
"gnomem_helmet",
"gnomem_armor",
"gnomem_boots",
"gnomem_amulet",
]
},
trib: {
rus: "Степного варвара",
arts: [
"sv_weap",
"sv_shield",
"sv_arb",
"sv_helm",
"sv_body",
"sv_boot",
]
},
utrib: {
rus: "Непокорного варвара",
arts: [
"nv_weap",
"nv_shield",
"nv_helm",
"nv_body",
"nv_boot",
]
},
templ: {
rus: "Рыцаря солнца",
arts: [
"kn_weap",
"kn_shield",
"kn_helm",
"kn_body",
]
},
inq: {
rus: "Инквизитора",
arts: [
"inq_weap",
"inq_cl",
"inq_helm",
"inq_body",
"inq_boot",
]
},
amph: {
rus: "Амфибии",
arts: [
"amf_weap",
"amf_scroll",
"amf_cl",
"amf_helm",
"amf_body",
"amf_boot",
]
},
surv: {
rus: "Сурвилурга",
arts: [
"surv_sword_surv",
"surv_axes",
"surv_halberdzg",
"surv_staffik",
"surv_scrollcd",
"surv_shieldvv",
"surv_sword2sd",
"surv_daggermd",
"surv_crossbowsurv",
"surv_cloacksrv",
"surv_mcloacksv",
"surv_helmetpi",
"surv_mhelmetcv",
"surv_armorsu",
"surv_marmoroz",
"surv_bootsurv",
"surv_mbootsbb",
"surv_wring1my",
"surv_wring2o",
"surv_mring1fd",
"surv_mring2fpg",
"surv_wamuletik",
"surv_mamulka",
]
},
tm_set: {
rus: "Времён",
arts: [
"staff_v1",
"staff_v2",
"staff_v3",
"vtmaxe1",
"vtmaxe2",
"vtmaxe3",
"vtmsword1",
"vtmsword2",
"vtmsword3",
"vrdagger1",
"vrdagger2",
"vrdagger3",
"tj-shield1",
"tj-shield2",
"tj-shield3",
"vscroll-1",
"vscroll-2",
"vscroll-3",
"vbow1",
"vbow2",
"vbow3",
"mtcloak1",
"mtcloak2",
"mtcloak3",
"vtjcloak1",
"vtjcloak2",
"vtjcloak3",
"tj_helmet1",
"tj_helmet2",
"tj_helmet3",
"mhelmv1",
"mhelmv2",
"mhelmv3",
"tjarmor1",
"tjarmor2",
"tjarmor3",
"tmarmor1",
"tmarmor2",
"tmarmor3",
"tj_vboots1",
"tj_vboots2",
"tj_vboots3",
"tj_mtuf1",
"tj_mtuf2",
"tj_mtuf3",
"v-ring1",
"v-ring2",
"v-ring3",
"vbolt1",
"vbolt2",
"vbolt3",
"vmring1",
"vmring2",
"vmring3",
"tjam1",
"tjam2",
"tjam3",
"tj_magam1",
"tj_magam2",
"tj_magam3",
"sph1",
"sph2",
"sph3",
]
},
mir_set: {
rus: "Мироходца",
arts: [
"mh_sword1",
"mh_sword2",
"mh_sword3",
"mir_bow1",
"mir_bow2",
"mir_bow3",
"mir_shld1",
"mir_shld2",
"mir_shld3",
"mir_cl1",
"mir_cl2",
"mir_cl3",
"mir_helmt1",
"mir_helmt2",
"mir_helmt3",
"mir_armor1",
"mir_armor2",
"mir_armor3",
"mir_boots1",
"mir_boots2",
"mir_boots3",
"mir_am1",
"mir_am2",
"mir_am3",
]
},
pir_set: {
rus: "Пирата",
arts: [
"p_sword1",
"p_sword2",
"p_sword3",
"p_dag1",
"p_dag2",
"p_dag3",
"p_pistol1",
"p_pistol2",
"p_pistol3",
"p_cloak1",
"p_cloak2",
"p_cloak3",
"piratehat1",
"piratehat2",
"piratehat3",
"pir_armor1",
"pir_armor2",
"pir_armor3",
"p_boots1",
"p_boots2",
"p_boots3",
"piring1",
"piring2",
"piring3",
"pn_ring1",
"pn_ring2",
"pn_ring3",
"p_amulet1",
"p_amulet2",
"p_amulet3",
"p_compas1",
"p_compas2",
"p_compas3",
]
},
leader_set: {
rus: "Полководца",
arts: [
"polk_sword1",
"polk_sword2",
"polk_sword3",
"polk__helm1",
"polk__helm2",
"polk__helm3",
"polk_armor1",
"polk_armor2",
"polk_armor3",
"polkboots1",
"polkboots2",
"polkboots3",
"gring",
"gringd",
]
},
undgr_set: {
rus: "Подземелий",
arts: [
"dung_axe1",
"dung_axe2",
"dung_axe3",
"dung_glefa1",
"dung_glefa2",
"dung_glefa3",
"dun_sword1",
"dun_sword2",
"dun_sword3",
"dun_dagger1",
"dun_dagger2",
"dun_dagger3",
"dun_shield1",
"dun_shield2",
"dun_shield3",
"dun_bow1",
"dun_bow2",
"dun_bow3",
"dun_cloak1",
"dun_cloak2",
"dun_cloak3",
"hm1",
"hm2",
"drak_crown1",
"drak_crown2",
"drak_crown3",
"drak_armor1",
"drak_armor2",
"drak_armor3",
"dun_armor1",
"dun_armor2",
"dun_armor3",
"dun_boots1",
"dun_boots2",
"dun_boots3",
"drak_greaves1",
"drak_greaves2",
"drak_greaves3",
"dun_ring1",
"dun_ring2",
"dun_ring3",
"dering",
"dun_amul1",
"dun_amul2",
"dun_amul3",
"crystal",
]
},
razb_set: {
rus: "Разбойника",
arts: [
"raxe1",
"raxe2",
"rsword1",
"rsword2",
"rdagger1",
"rdagger2",
"rshield1",
"rshield2",
"rbow1",
"rbow2",
"rcloak1",
"rcloak2",
"rhelm1",
"rhelm2",
"rarmor1",
"rarmor2",
"rboots1",
"rboots2",
"rogring1",
"rogring2",
"ramul1",
"ramul2",
"sumka",
]
},
ocean_set: {
rus: "Океана",
arts: [
"ocean_sword1",
"ocean_sword2",
"ocean_sword3",
"ocean_dgr1",
"ocean_dgr2",
"ocean_dgr3",
"ocean_m_shield1",
"ocean_m_shield2",
"ocean_m_shield3",
"ocean_bw1",
"ocean_bw2",
"ocean_bw3",
"ocean_cl1",
"ocean_cl2",
"ocean_cl3",
"ocean_hlm1",
"ocean_hlm2",
"ocean_hlm3",
"m_armor1",
"m_armor2",
"m_armor3",
"ocean_boots1",
"ocean_boots2",
"ocean_boots3",
"ocean_per1",
"ocean_per2",
"ocean_per3",
"ocean_ring1",
"ocean_ring2",
"ocean_ring3",
"m_amul1",
"m_amul2",
"m_amul3",
"ocean_eye1",
"ocean_eye2",
"ocean_eye3",
]
},
avan_set: {
rus: "Авантюриста",
arts: [
"adv_saber1",
"adv_saber2",
"a_dagger1",
"a_dagger2",
"adv_shild1",
"adv_shild2",
"adv_longbow1",
"adv_longbow2",
"adv_clk1",
"adv_clk2",
"adv_hm1",
"adv_hm2",
"adv_armor1",
"adv_armor2",
"adv_boot1",
"adv_boot2",
"adv_fring1",
"adv_fring2",
"adv_neck1",
"adv_neck2",
"adv_sumk1",
"adv_sumk2",
]
},
ed_set: {
rus: "Единства",
arts: [
"ed_bsword1",
"ed_bsword2",
"ed_bsword3",
"ed_mbook1",
"ed_mbook2",
"ed_mbook3",
"ed_elfbow1",
"ed_elfbow2",
"ed_elfbow3",
"ed_armr1",
"ed_armr2",
"ed_armr3",
"ed_svboots1",
"ed_svboots2",
"ed_svboots3",
"ed_ring1",
"ed_ring2",
"ed_ring3",
"eddem_ring1",
"eddem_ring2",
"eddem_ring3",
"ed_pendant1",
"ed_pendant2",
"ed_pendant3",
"ed_barrel1",
"ed_barrel2",
"ed_barrel3",
]
},
forest_set: {
rus: "Леса",
arts: [
"forest_blade",
"forest_dagger",
"shieldofforest",
"forest_knives",
"forest_bow",
"forest_crossbow",
"les_cl",
"forest_helm",
"forest_armor",
"forest_boots",
"forest_bolt",
"neut_ring",
"neut_amulet",
]
},
stalker_set: {
rus: "Ловчего",
arts: [
"stalker_dagger1",
"stalker_dagger2",
"stalker_dagger3",
"stalker_shid1",
"stalker_shid2",
"stalker_shid3",
"stalker_crsb1",
"stalker_crsb2",
"stalker_crsb3",
"stalker_cl1",
"stalker_cl2",
"stalker_hlm1",
"stalker_hlm2",
"stalker_hlm3",
"stalker_armour1",
"stalker_armour2",
"stalker_armour3",
"stalker_boot1",
"stalker_boot2",
"stalker_boot3",
"stalker_iring1",
"stalker_iring2",
"stalker_iring3",
"stalker_aml1",
"stalker_aml2",
"stalker_aml3",
]
},
armada_set: {
rus: "Армады",
arts: [
"arm_clk1",
"arm_clk2",
"arm_clk3",
"arm_cap1",
"arm_cap2",
"arm_cap3",
"arm_armor1",
"arm_armor2",
"arm_armor3",
"arm_bts1",
"arm_bts3",
"arm_bts2",
"arm_r1",
"arm_r2",
"arm_r3",
"arm_sekstant1",
"arm_sekstant2",
"arm_sekstant3",
]
},
wanderer_set: {
rus: "Странника",
arts: [
"wanderer_hat1",
"wanderer_hat2",
"wanderer_hat3",
"wanderer_armor1",
"wanderer_armor2",
"wanderer_armor3",
"wanderer_boot1",
"wanderer_boot2",
"wanderer_boot3",
]
},
};
// ====================
const DEV_ID = '5781303';
const MODULE_NAME = 'HWM_auction_upd';
const MODULE_VERSION = '2.1.6';
const MY_ID = document.cookie.match(/pl_id=(\d+)/)[1];
const AUC_PATH = location.pathname;
const modules = (function(symbol) {
return view[symbol] || (view[symbol] = {
stack: new Map,
has(key) { return this.stack.has(key); },
delete(key) { return this.stack.delete(key); },
get(key) { return this.stack.get(key); },
add(key, version, exports) {
if (this.stack.has(key)) return;
this.stack.set(key, { version, exports });
}
});
})(Symbol.for('__' + DEV_ID + '__'));
// ==================== [[ UTILS ]]
const $ = (selector, ctx = document) => ctx.querySelector(selector);
const $$ = (selector, ctx = document) => [...ctx.querySelectorAll(selector)];
const attempt = (that, callback) => that ? callback(that) : null;
const parseNum = (num) => `${num}`.replaceAll(',', '') >> 0;
const formatNum = (num) => num.toLocaleString('en');
const importNode = (node) => document.importNode(node, true);
function fetch({ url, method = 'GET', type = 'document', body = null }) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.responseType = type;
xhr.onload = () => {
if (xhr.status === 200) return resolve(xhr.response);
throwError(`Error with status ${xhr.status}`);
};
xhr.onerror = () => throwError(`HTTP error with status ${xhr.status}`);
xhr.send(body);
function throwError(msg) {
const err = new Error(msg);
err.status = xhr.status;
reject(err);
}
});
}
fetch.get = (url) => fetch({ url });
fetch.post = (url, data) => fetch({ url, method: 'POST', body: data });
function parseNode(html, callback) {
let elem = document.createElement('div');
elem.innerHTML = html;
elem = elem.firstElementChild.cloneNode(true);
callback && callback.call(elem, elem);
return elem;
}
function getAucURL(search) {
return AUC_PATH + (search || '?cat=my') + '&sbn=1&sau=1&snew=0';
}
function getSearchParams(search) {
const entries = [...new URLSearchParams(search)];
return entries.length ? Object.fromEntries(entries) : { cat: 'my' };
}
function debounce(callback, delay) {
let timerId = 0;
return function(e) {
clearTimeout(timerId);
timerId = setTimeout(callback, delay, e);
};
}
function throttle(callback, delay) {
let isPending = false;
return function(e) {
if (isPending) return;
isPending = true;
setTimeout(() => {
callback(e);
isPending = false;
}, delay);
};
}
function addImageToArt({search, style}) {
const path = 'https://dcdn.heroeswm.ru/i/artifacts/';
let key = search.split('=').pop();
if (key.startsWith('part_')) key = key.slice(5);
const src = allArtsData[key];
const id = !src ? '' : src === '&' ? key : src.replace('&', key);
if (src) style.backgroundImage = `url("${path + id}.png")`;
}
// ==================== [[ USER DATA ]]
const userDataKey = `${MODULE_NAME}__${MY_ID}`;
const userData = Object.assign({
playerName: '',
sort: 'byCost',
order: '1',
extSearch: false,
filters: { full: 1 },
bets: {},
faves: {},
newArts: {},
newSetArts: {},
pullPrevState(oldKey, key) {
const val = localStorage[oldKey];
if (!(val && val.startsWith('{') && val.endsWith('}'))) return;
delete localStorage[oldKey];
Object.assign(this[key], JSON.parse(val));
},
update(key, value) {
if (key && value !== undefined) this[key] = value;
localStorage[userDataKey] = this.toString();
},
toString() {
return JSON.stringify(this);
}
}, JSON.parse(localStorage[userDataKey] || '{}'));
if (!userData.hasOwnProperty('v')) {
userData.pullPrevState(`newAucBets_${MY_ID}`, 'bets');
userData.pullPrevState(`newAucChosen_${MY_ID}`, 'faves');
userData.pullPrevState('newAucArts', 'newArts');
userData.pullPrevState('newAucSetArts', 'newSetArts');
}
const isOldVersion = userData.v === MODULE_VERSION;
if (!isOldVersion) {
userData.newArts = {};
userData.newSetArts = {};
userData.update('v', MODULE_VERSION);
}
// ==================== [[ CSS ]]
const mainStyle = parseNode('<style></style>', function() {
this.append(/*css*/`
@charset "utf-8";
/* COMMON */
:root {
font-size: 10px;
}
::before,
::after {
box-sizing: border-box;
}
* {
font-family: inherit;
font-size: inherit;
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
height: 100vh;
position: relative;
background-image: linear-gradient(45deg, black, #353741);
overflow: hidden !important;
}
body > :not(#auction) {
display: none !important;
}
button {
cursor: pointer;
}
img {
max-width: 100%;
vertical-align: middle;
pointer-events: none;
}
a,
button,
input {
color: inherit;
border: none;
outline: none;
text-decoration: none;
}
a span {
pointer-events: none;
}
@keyframes spin {
to {
transform: rotate(1turn);
}
}
.ui-scroll {
overflow-x: hidden;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: #ccc #52525d;
}
.ui-scroll::-webkit-scrollbar {
width: .5rem;
background-color: #696969;
}
.ui-scroll::-webkit-scrollbar-thumb {
min-height: 4rem;
background-color: #aaa;
}
[href*="auction.php"]:hover {
color: #cfbba0;
}
/* TOP */
#auction {
--active-link-fg: #ffe762;
--active-link-bg: #b2c5422e;
--player-link-fg: #59d4b6;
font-family: Arial, sans-serif;
font-size: 1.6rem;
width: 100%;
min-width: 90rem;
height: inherit;
min-height: 60rem;
position: absolute;
left: 0;
top: 0;
color: #eee;
background-color: #494751;
user-select: none;
}
#auction.__loading::after,
#auction.__disconnected::after {
content: "";
position: absolute;
left: 5rem;
right: 0;
top: 0;
bottom: 0;
background-color: #3c4a57;
opacity: .3;
z-index: 1;
}
#auction.__disconnected::after {
opacity: .1;
z-index: 4;
}
#auction__header {
height: 5rem;
line-height: 5rem;
display: flex;
align-items: center;
column-gap: 1rem;
position: relative;
padding: 0 1.2rem;
border-bottom: 1px solid #1a1a1a;
z-index: 1;
}
.__unallowed > #auction__header {
background-image: linear-gradient(45deg, #5e2c2c, transparent);
}
#online {
--size: 2.5rem;
--hue: 157deg;
--color1: hsl(var(--hue), 80%, 80%);
--color2: hsl(var(--hue), 100%, 55%);
--color3: hsl(var(--hue), 100%, 40%);
width: var(--size);
height: var(--size);
display: inline-block;
position: relative;
border-radius: 50%;
}
@keyframes blinkOnLine1 {
0%, 20%, 50%, 70%, 100% { opacity: 1; }
40%, 60% { opacity: .5; }
}
@keyframes blinkOnLine2 {
to { filter: drop-shadow(0 0 6px red); }
}
.__disconnected #online {
--hue: 345deg;
animation:
blinkOnLine1 1s ease-in-out 2,
blinkOnLine2 1s 2s ease-in-out infinite alternate;
}
#online::after {
content: "";
position: absolute;
left: .7rem;
right: .7rem;
top: .7rem;
bottom: .7rem;
background: radial-gradient(var(--color1) 30%, var(--color2));
border-radius: inherit;
filter: drop-shadow(0 0 3px var(--color3));
}
#refresh {
font-size: 1.3em;
letter-spacing: .5rem;
text-transform: uppercase;
filter: drop-shadow(2px 2px 2px black);
}
#refresh:hover {
filter: sepia(1) drop-shadow(2px 2px 2px black);
}
@supports ((background-clip: text) or (-webkit-background-clip: text)) {
@keyframes aucBgMove {
to { background-position-x: -150%; }
}
#refresh {
color: transparent;
background-image: linear-gradient(45deg, #00bfff, #64cccc, #8ed8ab, #f5e275, #8ed8ab, #64cccc, #00bfff);
background-size: 300%;
background-clip: text;
-webkit-background-clip: text;
animation: aucBgMove 4s ease-in-out infinite;
}
}
#author {
color: #aaa;
}
#author:hover {
color: tan;
}
#author::before {
content: "© ";
color: #aaa;
}
/* RESOURCES */
#resources {
flex: 1;
display: inline-flex;
justify-content: flex-end;
column-gap: 1.4rem;
}
.resources__item::after {
content: attr(data-value);
}
.resources__item:first-child::after {
color: gold;
}
.resources__item > a {
color: inherit;
background-color: transparent;
}
/* MENU */
#auction__container {
--container-height: calc(100% - 5rem);
height: var(--container-height);
display: flex;
}
#aside_1 {
width: 5rem;
min-width: 5rem;
height: 100%;
position: relative;
color: #ddd;
}
.menu:hover {
background-color: #2d2c33;
outline: 1px solid #666;
}
.menu:focus-within {
background-color: #2d2c33;
outline: 1px solid #666;
}
.menu__link {
display: block;
padding: .5rem 0;
}
.menu__icon {
filter: saturate(.5);
}
.menu:hover .menu__icon {
filter: saturate(1);
}
.menu__list {
width: 26.8rem;
height: var(--container-height);
display: none;
position: absolute;
left: 100%;
top: 0;
margin-left: 1px;
background-color: inherit;
z-index: 1;
}
.menu:hover .menu__list {
display: block;
}
.__disconnected .menu__list {
z-index: 5;
}
.menu__list::before {
content: "# " attr(data-name);
display: block;
padding: 1rem;
text-transform: uppercase;
color: tan;
border-bottom: 1px solid #444;
}
.menu__list::after {
content: "";
width: 2px;
position: absolute;
left: -1px;
top: 0;
bottom: 0;
}
a.menu__item {
display: block;
position: relative;
padding: .8rem 1.2rem;
color: inherit;
background-color: inherit;
border-bottom: 1px solid #444;
overflow: hidden;
}
.menu__item:hover,
.menu__item:focus {
color: #cfbba0;
background-color: #383740;
}
.menu__item::after {
content: "";
font-size: 2.5em;
width: 4em;
height: 4em;
position: absolute;
left: -2em;
top: -2em;
background-image: radial-gradient(50% 50%, white, transparent);
opacity: 0;
transform: translate(var(--x, 0), var(--y, 0));
transition: opacity .2s;
pointer-events: none;
}
.menu__item:hover::after {
opacity: .15;
}
/* PLAYER */
#aside_2 {
width: 27rem;
min-width: 27rem;
height: 100%;
position: relative;
background-color: #2d2c33;
border-left: 1px solid #555;
border-right: 1px solid #444;
overflow: hidden;
}
#player {
height: 7rem;
display: flex;
flex-direction: column;
justify-content: space-around;
justify-content: space-evenly;
padding-left: 1rem;
}
#player__name {
color: tan;
}
#player__name:hover {
filter: saturate(1.2) brightness(1.2);
}
.gold {
vertical-align: middle;
}
#player__gold {
font-size: 1.2em;
color: gold;
}
.coin {
font-size: 1.2rem;
width: 1.5em;
line-height: 1.5em;
display: inline-block;
vertical-align: middle;
margin-left: .5em;
text-align: center;
color: #927008;
background-color: #ffcc33;
border-radius: 50%;
box-shadow: inset 0 0 0 .2em #c79600;
}
#coin {
font-size: 1.8rem;
position: relative;
margin-left: 0;
margin-right: .25em;
background-image: linear-gradient(145deg, #ffc001, #ffd900, #cc9900);
}
#coin::before {
content: "";
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: .1em;
border: .1em solid #917317;
border-radius: inherit;
}
/* CATEGORIES */
#categories {
height: calc(100% - 12rem);
display: flex;
flex-direction: column;
color: #aaa;
background-color: #313038;
border-top: 1px solid #444;
}
.category.__active {
color: #eee;
background-color: #2b3a4c75;
}
.category.__active,
.category__heading {
border-bottom: 1px solid #444;
}
.category__heading {
--selected-bg: #38424f;
height: 3.4rem;
line-height: 3.4rem;
font-weight: normal;
position: relative;
top: 0;
padding: 0 2.4rem 0 1rem;
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.category__heading:hover {
background-color: #33405175;
}
.category.__active .category__heading {
position: sticky;
background-color: #3c4754;
}
.category__heading::after {
content: "▼";
font-size: .6em;
position: absolute;
top: 0;
right: 0.7rem;
opacity: .7;
}
.category.__active .category__heading::after {
content: "▲";
}
.category__items {
--count: 0;
font-size: .9em;
height: calc(2.8rem * var(--count));
transition: height .4s;
transition-duration: max(.4s, var(--count) * .015s);
overflow: hidden;
}
.category__item {
height: 2.8rem;
line-height: 2.7rem;
display: block;
padding: 0 1rem;
color: #a0b1bb;
border-top: 1px solid #495055;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.category__item[style] {
text-indent: 2.5rem;
background-repeat: no-repeat;
background-position: 1rem 50%;
background-size: 1.6rem;
}
.category__item:first-child {
border-top: none;
}
.category__item:hover,
.category__item:focus {
background-color: #3f4b5a75;
}
.category__item:not([style])::before {
content: "•";
float: left;
margin-right: .8rem;
text-indent: 0;
color: #aaa;
}
.category__all {
font-size: .8em;
min-width: 3.6rem;
float: right;
text-align: center;
color: #d1bfa8;
pointer-events: auto;
}
.category__all:hover,
.category__all:focus {
color: #94d4da;
}
#cat-my .category__heading {
pointer-events: none;
}
#cat-my .category__heading::after {
display: none;
}
#new-lot {
height: 5rem;
line-height: 5rem;
text-align: center;
color: #aaa;
border-top: 1px solid #444;
}
#new-lot > a {
color: #d1bfa8;
}
#new-lot > a:is(:hover, :focus) {
text-decoration: underline;
}
/* TOP STUFF */
#main {
flex: 1;
width: calc(100% - 32rem);
min-width: 86rem;
height: 100%;
display: flex;
flex-direction: column;
position: relative;
background-color: #201f24;
counter-reset: lot;
}
.main__top {
height: 5rem;
display: flex;
justify-content: flex-start;
align-items: center;
padding: .7rem;
}
.main__top:first-child {
background-color: #2b2b33;
border-bottom: 1px solid #444;
}
.a-box {
width: 20rem;
height: 100%;
position: relative;
margin-right: 1rem;
background-color: #3a404e;
box-shadow: 0 0 3px #000;
}
.a-box:last-child {
margin-right: 0;
margin-left: auto;
}
.__unallowed .a-box {
color: gray;
filter: grayscale(.7);
pointer-events: none;
}
.a-box::after {
content: "";
height: 4px;
position: absolute;
left: 0;
right: 0;
top: 100%;
}
.a-btn {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
column-gap: .5em;
background-color: transparent;
}
.a-btn:focus {
outline: 2px solid #57d6cf5b;
outline-offset: -3px;
}
.a-btn::before {
width: 1.6rem;
height: 1.6rem;
background: center / contain;
filter: sepia(1) brightness(2);
}
#artlist-btn::before {
content: "";
background-image: url("https://dcdn.heroeswm.ru/i/help/help_ico11.png");
}
#setlist-btn::before {
content: "";
background-image: url("https://dcdn.heroeswm.ru/i/help/help_ico40.png");
}
#faves-btn::before {
content: "";
background-image: url("https://dcdn.heroeswm.ru/i/pl_info/services/icon_Clans.png");
}
#artlist-eye {
font-size: 1.4em;
line-height: 1;
color: gray;
}
#artlist-eye:hover {
color: #b8b3ac;
}
#artlist-eye.__switched-on {
color: #a2c5cd;
}
/* ART LIST */
@keyframes listFadeIn {
from { filter: opacity(0); transform: translateY(0); }
to { filter: opacity(1); transform: translateY(4px); }
}
@keyframes listVisibility {
from { visibility: hidden; }
to { visibility: visible; }
}
.a-list {
min-width: 100%;
max-width: 28rem;
max-height: 36rem;
line-height: 2;
display: none;
position: absolute;
left: 0;
top: 100%;
background-color: #41414b;
border: 1px solid #555;
box-shadow: 2px 2px 4px #161616;
transform: translateY(4px);
z-index: 3;
}
.a-box:hover .a-list,
:focus + .a-list {
display: block;
animation: listVisibility .15s steps(1), listFadeIn .25s .15s backwards;
}
.a-list:focus-within {
display: block;
animation: listVisibility .15s steps(1), listFadeIn .25s .15s backwards;
}
.a-box:hover .a-list {
z-index: 4;
}
.a-list:empty {
display: none !important;
}
.a-list::before,
.a-list::after {
content: "";
height: 1.4rem;
display: block;
position: sticky;
top: -1px;
background: linear-gradient(#41414b 30%, transparent);
pointer-events: none;
z-index: 1;
}
.a-list::after {
top: auto;
bottom: -1px;
transform: scaleY(-1);
}
.a-list__item {
display: block;
padding: 0 1rem;
color: #bbb;
border-bottom: 1px solid #555;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.a-list__item:first-child {
border-top: 1px solid #555;
}
.a-link[style] {
text-indent: 3.4rem;
background-repeat: no-repeat;
background-position: 1rem 50%;
background-size: 2.5rem;
}
.a-list__item:hover,
.a-list__item:focus {
background-color: #36363f;
}
.a-box .__left {
width: calc(100% - 4rem);
float: left;
}
/* SET LIST */
.setlist__set {
border-top: 1px solid #555;
}
.setlist__set:last-child {
border-bottom: 1px solid #555;
}
.setlist__set-name {
font-weight: inherit;
padding: 0 3rem 0 1rem;
background-color: #3c3c45;
white-space: nowrap;
}
.setlist__set-name:hover {
filter: saturate(1.2) brightness(1.2);
}
.setlist__set-name::before {
content: "@ сет";
margin-right: .5em;
color: #c9bba8;
}
.setlist__set-name::after {
content: "+";
position: absolute;
right: 1rem;
color: #aaa;
}
.setlist__set.__active .setlist__set-name::after {
content: "-";
}
.setlist__arts {
display: none;
text-indent: 1rem;
}
.setlist__set.__active .setlist__arts {
display: block;
}
.setlist__arts:empty::before {
content: "Нет на рынке";
display: block;
padding-left: 1rem;
color: #f0b1b1;
border-top: 1px solid #555;
}
.setlist__arts :last-child {
border-bottom: none;
}
/* SEARCH */
#search-box {
width: 26rem;
box-shadow: none;
}
.a-input {
height: 100%;
padding: 0 3rem 0 .6rem;
color: lightblue;
background-color: #1a1a1a;
box-shadow: inset -1px -1px 1px #555;
user-select: auto;
}
.a-input:focus {
box-shadow: inset 0 0 2px #57d6cf;
}
.action {
width: 4rem;
height: 100%;
float: right;
color: #bbb;
background-color: #344259;
outline: 2px solid #646363;
outline-offset: -3px;
}
.action:hover {
background-color: #3f4e67;
}
.action:active {
transform: scale(.9);
}
.action.__active {
color: #83add4;
outline-color: #57d6cf5b;
}
#ext-search {
font-size: .8em;
}
#search-reset {
font-size: 1.6em;
width: 3rem;
line-height: 3.4rem;
position: absolute;
right: 4rem; top: 0;
color: #bbb;
text-align: center;
visibility: hidden;
cursor: pointer;
}
#search-reset:hover {
color: inherit;
}
#search-reset.__shown {
visibility: visible;
}
#select-link {
position: relative;
color: #d3ad7b;
background-color: #31313c;
z-index: 2;
}
/* FAVES */
#faves-btn.__none {
background-color: #666;
text-decoration: line-through;
pointer-events: none;
opacity: .5;
}
#faves {
left: auto;
right: 0;
}
.fave-item {
position: relative;
padding-right: calc(2rem + 1em);
}
[data-fave-action="remove"] {
position: absolute;
right: 0;
top: 0;
bottom: 0;
text-indent: 0;
padding: 0 1rem;
color: #eee;
visibility: hidden;
cursor: pointer;
pointer-events: auto;
}
[data-fave-action="remove"]:hover {
color: #fa9696;
}
.fave-item:hover > [data-fave-action="remove"] {
visibility: visible;
}
#faves-input-box {
width: 26rem;
height: 100%;
display: none;
position: absolute;
right: calc(100% + 1rem);
top: 0;
}
.__active ~ #faves-input-box {
display: block;
}
/* FILTERS */
#filters-icon {
fill: wheat;
}
#filters-box.__disabled,
#filters-box.__disabled #filters-icon {
color: gray;
filter: grayscale(.7);
pointer-events: none;
}
#filters-counter {
position: absolute;
left: calc(100% + 1rem); top: 1rem;
color: #aaa;
pointer-events: none;
}
#filters {
min-width: 24rem;
white-space: nowrap;
}
.filters__group {
display: flex;
border-bottom: 1px solid #5a5a5a;
}
.filters__group:first-child {
border-top: 1px solid #5a5a5a;
}
.filters__item {
width: 50%;
padding: 0 1rem;
color: #bbb;
}
.filters__item:hover {
background-color: #36363f;
}
.filters__item:first-child {
border-right: 1px solid #5a5a5a;
}
.filters__item.__active {
color: #cfbba0;
background-color: #424b5d;
}
.__partial .filters__group:nth-child(n+2) .filters__item {
color: #6e6e6e;
background-color: transparent;
pointer-events: none;
}
/* SORTS */
#sorts {
height: 4rem;
display: flex;
padding-right: .5rem;
color: #aaa;
background-color: #2e2d36;
border: 1px solid #41434a;
border-width: 1px 0;
overflow: hidden;
}
.a-td {
width: calc(100% - 32rem);
min-width: 10rem;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
text-align: center;
padding: 0 .5rem;
border-right: 1px solid #41434a;
overflow: hidden;
}
.a-td:last-child {
border-right: none;
}
._name {
min-width: 32rem;
padding-left: 0;
}
._name,
.sorts__item {
flex-direction: row;
justify-content: center;
}
.sorts__item:hover {
color: #81b0d8;
cursor: pointer;
}
.sorts__item[data-order]::after {
content: "▲";
font-size: .7em;
width: 0;
display: inline-block;
position: relative;
left: .8rem;
color: #aaa;
}
.sorts__item[data-order="0"]::after {
content: "▼";
}
/* LOT */
@keyframes lotLoading {
0% { content: ""; }
25% { content: "."; }
50% { content: ".."; }
75% { content: "..."; }
}
.lot__processing {
font-family: Consolas, monospace;
font-size: 1.2em;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
color: #eee;
background-color: #333a;
z-index: 1;
}
.lot__loading::after {
content: "";
width: 0;
display: inline-block;
animation: lotLoading .5s steps(1) infinite;
}
#lots-container {
flex: 1;
position: relative;
}
#lots-container::before {
content: "Лотов не найдено, мяу ^_^";
line-height: 2;
position: absolute;
left: 0; right: 0;
padding: 1em;
text-align: center;
color: #bbb;
border-bottom: 1px solid #333;
}
.__unallowed #lots-container::before {
content: "Рынок не доступен!";
color: #d85c5c;
}
#lots {
width: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
position: relative;
background-color: #201f24;
border-bottom: 1px solid #3c3e46;
overflow: hidden;
}
#lots[data-order="0"] {
flex-direction: column-reverse;
}
.lot {
--lot-bg: inherit;
--lot-2n-bg: #22242c;
counter-increment: lot;
font-size: .9em;
height: 8.5rem;
display: flex;
justify-content: space-between;
position: relative;
color: #ddd;
background-color: var(--lot-bg);
border-top: 1px solid #3c3e46;
overflow: hidden;
}
.lot[data-cat="obj_share"] {
height: 11rem;
}
.lot:nth-child(even) {
background-color: var(--lot-2n-bg);
}
.lot:hover,
.lot.__hovered {
background-image: linear-gradient(to right, #3a2727cc, transparent);
}
.lot[data-params*="mybet=1"] {
--lot-bg: #34504d3d;
--lot-2n-bg: #34504559;
}
.lot[data-params*="completed=1"] {
color: #aaa;
background-color: #3339;
filter: grayscale(1) opacity(.8);
pointer-events: none;
}
.lot[data-params*="mylot=1"] {
--lot-bg: #2c3b5ab2;
--lot-2n-bg: #28364eb2;
}
.lot[data-params*="mylot=1"][data-params*="once=0"] {
filter: grayscale(.35);
}
.lot.__active {
background-image: linear-gradient(to right, #33485fcc, transparent);
outline: 1px solid #4e8fb8;
z-index: 1;
}
.lot .a-td {
pointer-events: none;
}
.lot a {
pointer-events: auto;
}
.lot__box {
min-width: 8.4rem;
height: 100%;
display: block;
position: relative;
color: inherit !important;
background-color: transparent !important;
}
.lot__img {
width: 5rem;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
}
.lot__amount {
position: absolute;
right: 2px;
bottom: 2px;
}
.lot__info {
width: calc(100% - 7rem);
height: 100%;
padding: 0 .8rem;
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: flex-start;
text-align: left;
overflow: hidden;
}
.lot__id {
color: #aaa;
}
.lot__id::before {
content: "#";
color: #c9bba8;
}
.lot__name {
max-width: 100%;
color: #dda94a;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.lot__durability {
letter-spacing: 1px;
}
.lot__durability::before {
content: "Прочность: ";
letter-spacing: normal;
color: #ccc;
}
[data-cat="part"] .lot__durability::before {
content: "Частей: ";
}
.mods-scope {
color: #ccc;
}
.mods-scope::before {
content: "Крафт: [ ";
}
.mods-scope::after {
content: " ]";
}
.art-mods {
width: .6rem;
display: flex;
flex-direction: column;
row-gap: .4rem;
position: absolute;
left: .5rem;
top: 1rem;
}
.a-td._type {
position: relative;
}
.lot__bet-type {
color: tan;
}
.mybet::before {
content: "Ваша ставка: ";
color: tan;
}
.i-watch {
font-size: 1.2em;
line-height: 1;
position: absolute;
left: .5rem;
top: .3rem;
color: #a5a5a5;
text-shadow: 0 0 2px black;
cursor: help;
pointer-events: auto;
}
/* LOT TIMERS */
@keyframes timerTicking {
to { opacity: .65; }
}
.lot[style*="--timer"] .lot__time {
display: none;
}
.lot[style*="--timer"] > ._time::after {
content: var(--timer);
color: orange;
}
.lot[style*="00:"] > ._time::after {
color: lightcoral;
animation: timerTicking .5s ease-in-out infinite alternate;
}
.lot[style*="00:00"] > ._time::after {
content: "00:00";
animation: none;
}
/* FORM */
@keyframes formSending {
to { background-position-x: -150%; }
}
#form {
background-color: #262b39;
}
#form > header {
height: 5rem;
line-height: 5rem;
padding: 0 1em;
border-top: 1px solid #545e73;
}
#form > header::after {
content: counter(lot);
margin-left: .4em;
color: tan;
}
#form__lot {
background: transparent;
border: 0 solid #4f5058;
border-width: 1px 0;
}
#form > footer {
height: 5rem;
padding-left: 1em;
display: flex;
justify-content: flex-start;
align-items: center;
}
#form.__minimized > :not(header) {
display: none;
}
#form__input {
width: 6em;
padding: 4px;
margin-left: .5rem;
color: #ccbeac;
background-color: #222;
border: 1px solid #545454;
outline: 1px solid transparent;
}
#form__input:invalid {
border-color: tomato;
}
#form__submit {
--bg: #3b6369;
min-width: 14rem;
position: relative;
padding: 4px;
margin-left: 1rem;
background-color: var(--bg);
background-image: linear-gradient(var(--bg), #3a404e);
border: 1px solid gray;
}
#form__submit:hover,
#form__submit:focus {
--bg: #5a768e;
}
#form__submit:active {
transform: scale(.95);
}
#form__submit > span {
position: relative;
text-shadow: 0 0 2px black;
z-index: 1;
}
#form__submit.__sending::before {
content: "";
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-image: linear-gradient(120deg, transparent 20%, #fff 50%, transparent 80%);
background-size: 150% 100%;
background-position: 150% 0;
opacity: .7;
animation: formSending .7s linear infinite;
}
#form :disabled {
color: #aaa;
background: #666;
pointer-events: none;
}
/* ALERT */
@keyframes userAlertProcessing {
to { width: 100%; }
}
@keyframes userAlertStart {
from { filter: opacity(0); }
to { filter: opacity(1); }
}
#notices {
display: flex;
flex-direction: column;
row-gap: .5rem;
position: absolute;
left: 1rem;
bottom: 6rem;
z-index: 5;
}
.user-alert {
--h: 200;
--s: 64%;
font-size: .875em;
width: 26em;
line-height: 1.3;
position: relative;
color: hsl(var(--h), var(--s), 42%);
background: linear-gradient(45deg, #222, #444);
border: 2px solid currentColor;
outline: 1px solid black;
animation: userAlertStart .35s;
}
.user-alert.__warn {
--h: 45;
}
.user-alert.__error {
--h: 0;
}
.user-alert.__success {
--h: 150;
}
.user-alert::before {
content: "";
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: currentColor;
opacity: 0.125;
}
.user-alert:hover::before,
.user-alert:focus::before {
opacity: 0.25;
}
.user-alert:focus-within::before {
opacity: 0.25;
}
.user-alert__body {
position: relative;
padding: 0.8em;
padding-right: 1.8em;
margin-bottom: 2px;
color: hsl(var(--h), var(--s), 90%);
text-shadow: 0 0 2px black;
white-space: pre-line;
}
.user-alert__close {
font-size: 1.5em;
width: 1.2em;
height: 1.2em;
position: absolute;
right: 1px;
top: 1px;
color: #bbb;
background: transparent;
border: none;
outline: none;
text-shadow: 0 0 2px black, 0 0 2px black;
z-index: 2;
}
.user-alert__close:hover {
color: white;
}
.user-alert__close:focus {
color: #ff7474;
}
.user-alert.__finite::after {
content: "";
width: 0;
height: 2px;
position: absolute;
left: 0;
bottom: 0;
background-color: darkseagreen;
animation: userAlertProcessing 5s linear 1s;
}
.user-alert.__finite:hover::after,
.user-alert.__finite:focus::after {
animation-play-state: paused;
}
.user-alert.__finite:focus-within::after {
animation-play-state: paused;
}
/* ART INFO */
#art-info {
font-size: 1.4rem;
line-height: 1.3;
min-width: 70rem;
max-width: 82rem;
display: flex;
position: absolute;
left: var(--x);
top: var(--y);
color: #ddd;
background-color: #262a39;
background-image: linear-gradient(45deg, #202140, #2d4956);
border: 2px solid #325e7d;
box-shadow: 0 0 4px 2px #111;
opacity: 0;
visibility: hidden;
transition: opacity .1s, visibility .1s;
z-index: 4;
}
#art-info:hover,
#art-info.__shown {
opacity: 1;
visibility: visible;
}
#art-info:hover::before,
#art-info.__shown::before {
content: "";
width: 11rem;
position: absolute;
left: -1.4rem;
top: -5rem;
bottom: -5rem;
z-index: -1;
}
.global_container_block_header {
position: absolute;
right: 2rem;
top: 2rem;
text-transform: uppercase;
filter: saturate(3);
}
.art_info_left_block {
padding: 2rem 1rem 2rem 2rem;
}
.s_art_prop_amount_icon {
min-height: 3rem;
display: flex;
justify-content: center;
align-items: center;
margin-top: 2px;
color: #eee;
background-color: #3b4b69;
background-image: linear-gradient(#5f8d84, #2c4168);
border: 1px solid #78878d;
}
.s_art_prop_amount_icon:hover {
filter: saturate(1.5);
}
.s_art_prop_amount_icon:active {
transform: scale(.95);
}
.s_art_prop_amount_icon img {
width: 2rem;
margin-right: .5rem;
}
#art-info .cre_mon_image1 {
display: none;
}
.art_info_desc {
padding: 2rem;
background: transparent !important;
}
#art-info .rs {
margin: 0 2px;
}
#art-info font {
color: inherit;
}
#art-info td {
color: #ddd;
}
#art-info b {
color: #bfb3a2;
}
#art-info i {
color: #9fbec8;
}
#art-info [href*="section=40"] {
color: #70b27d;
text-decoration: underline;
}
.s_art_inside > br:last-child {
display: none;
}
/* HOUSE STUFF */
@font-face {
font-family: "Material Icons";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url("https://fonts.gstatic.com/s/materialicons/v98/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2") format("woff2");
}
.m-icon {
font-family: "Material Icons", Arial, sans-serif;
font-size: 2rem;
line-height: 1;
display: inline-block;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
}
[data-cat="dom"] .lot__info {
position: relative;
}
.obj-id {
filter: saturate(.5) brightness(1.1);
}
.place {
color: #98bebb;
}
.house__stars {
position: absolute;
right: .5rem; top: 1rem;
}
.house__star {
font-size: 1.4rem;
color: #e6d78a;
}
/* LOADER */
#loader {
width: 5rem;
height: 5rem;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
color: skyblue;
border-radius: 50%;
box-shadow: inset -2px -2px 2px;
visibility: hidden;
filter: opacity(0);
transition: filter .3s .1s, visibility .3s .1s;
animation: spin 1s linear infinite;
z-index: 2;
}
.__loading > #loader {
visibility: visible;
filter: opacity(1);
transition-delay: 0s;
will-change: filter;
}
/* BETS */
#mybets-btn.__active {
background-color: #344342;
}
#mybets-btn[data-counter="0"]:not(.__active) {
color: gray;
background-color: #3e4044;
pointer-events: none;
}
#mybets-btn[data-counter]::after {
content: "( " attr(data-counter) " )";
color: #aaa;
}
/* CONTEXTMENU */
.contextmenu-is-shown::after {
content: "";
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 1;
}
#contextmenu {
font-size: .9em;
width: 40rem;
position: absolute;
left: var(--x);
top: var(--y);
padding: .5rem 0;
color: #ccc;
background-color: #2f2f2f;
border: 1px solid #555;
outline: none;
box-shadow: 2px 2px 2px rgba(0, 0, 0, .5);
z-index: 2;
}
#contextmenu:empty {
display: none;
}
.contextmenu__item {
line-height: 2;
padding: 0 1rem;
}
.contextmenu__item.__active {
background-color: #444;
}
.contextmenu__item::before {
content: attr(data-key);
float: right;
margin-left: 1rem;
opacity: .7;
}
.contextmenu__item:last-child {
margin-top: 1rem;
position: relative;
}
.contextmenu__item:last-child::after {
content: "";
height: 1px;
position: absolute;
left: 0;
right: 0;
top: -.6rem;
background-color: #444;
pointer-events: none;
}
/* CHANGELOG */
.user-alert.__changelog {
width: 46em;
}
#changelog {
max-height: 33em;
padding-right: 1em;
white-space: normal;
}
#changelog::before {
content: "Changelog";
font-size: 1.5em;
font-weight: bold;
display: block;
color: #c3b39e;
}
.cl-build {
font-size: 1.2em;
font-weight: bold;
margin: 0.5em 0;
color: #ccc;
}
.changelog-item::before {
content: "•";
margin-right: 0.3em;
color: #ccc;
}
kbd {
font-family: Consolas, monospace;
padding: 0 0.4em;
color: #000;
background-color: #909090;
border: 1px solid;
border-radius: 2px;
text-shadow: none;
}
/* ============== */
[href^="/pl_info"] {
color: lightblue;
}
.c-set {
color: #78ac78;
}
.lot a:hover,
.lot a:focus {
color: #db8779;
}
.__disconnected a[href^="/auction."] {
color: gray;
pointer-events: none;
}
@media screen and (max-width: 1320px) {
#aside_2 {
width: 0;
min-width: auto;
}
#aside_2:hover,
#aside_1:hover + #aside_2 {
width: 27rem;
min-width: 27rem;
}
}
@media screen and (max-width: 960px), screen and (max-height: 600px) {
:root {
font-size: 9px;
}
}
`);
});
const extraStyle = document.createElement('style');
extraStyle.__replace = function(ind, search, replacement) {
const node = this.childNodes[ind];
node.data = node.data.replace(search, replacement);
};
extraStyle.append(/*css*/`
#cat-CAT > h4 {
background-color: var(--selected-bg);
}
[href$="type=TYPE"] {
color: var(--active-link-fg);
background-color: var(--active-link-bg);
}
`);
extraStyle.append(/*css*/`
[href="/pl_info.php?id=${MY_ID}"],
[href="/pl_info.php?nick=${userData.playerName || 'NAME'}"] {
color: var(--player-link-fg);
}
`);
document.head.replaceChildren(
parseNode('<title>Рынок</title>'),
mainStyle,
extraStyle,
);
// ==================== [[ RENDER ]]
const aucElem = parseNode(/*html*/`
<main id="auction">
${renderHeader()}
<div id="auction__container">
<aside id="aside_1">${renderNav()}</aside>
<aside id="aside_2">
${renderPlayer(userData.playerName)}
<nav id="categories" class="ui-scroll"></nav>
<footer id="new-lot">
<a href="/auction_new_lot.php">Выставить лот</a>
</footer>
</aside>
<section id="main">
<div class="main__top">
<div class="a-box">
<button id="artlist-btn" class="a-btn">
Все артефакты
<span id="artlist-eye">👁</span>
</button>
<div id="artlist" class="ui-scroll a-list"></div>
</div>
<div class="a-box">
<button id="setlist-btn" class="a-btn">Комплекты</button>
<div id="setlist" class="ui-scroll a-list"></div>
</div>
<div class="a-box" id="search-box">
<input id="search" class="a-input __left" type="text" placeholder="Найти лот... (Ctrl + /)" spellcheck="false" autocomplete="off">
<div id="search-list" class="ui-scroll a-list"></div>
<button id="ext-search" class="action${userData.extSearch ? ' __active' : ''}" title="Поиск в подстроках (Alt+S)">*Aa*</button>
<span id="search-reset" title="Reset (Esc)">×</span>
</div>
${renderFaves(Object.keys(userData.faves).length)}
</div>
<div class="main__top">
${renderFilters(userData)}
<div id="mybets-box" class="a-box">
<button id="mybets-btn" class="a-btn" data-counter="0">Мои ставки</button>
</div>
</div>
${renderSorters(userData)}
<div id="lots-container" class="ui-scroll">
<section id="lots" data-order=${userData.order}></section>
</div>
${renderForm()}
<div id="notices"></div>
</section>
</div>
<div id="contextmenu" tabindex="-1"></div>
<div id="loader"></div>
<div id="art-info"></div>
</main>
`);
const aucClassList = aucElem.classList;
if (document.body) insertContainer();
function insertContainer() {
if (!aucElem.parentNode) document.body.prepend(aucElem);
}
function renderHeader() {
return /*html*/`
<header id="auction__header">
<span id="online" title="Статус интернет-соединения"></span>
<a id="refresh" href="${AUC_PATH}">Auction</a>
<span id="version">${MODULE_VERSION}</span>
<a id="author" href="/pl_info.php?id=${DEV_ID}">Мифист</a>
<div id="resources"></div>
</header>
`;
}
function renderNav() {
const navData = {
Character: [
['Персонаж', '/home.php'],
['Я', `/pl_info.php?id=${MY_ID}`],
['Протокол передач', `/pl_transfers.php?id=${MY_ID}`],
['Инвентарь', '/inventory.php'],
['Магазин артефактов', '/shop.php'],
['Рынок', AUC_PATH],
['Рынок: выставить лот', '/auction_new_lot.php'],
['Набор армии', '/army.php'],
['Замок', '/castle.php'],
['Навыки', '/skillwheel.php'],
['Личная почта', '/sms.php'],
['Передача ресурсов', '/transfer.php'],
['Передача элементов', '/el_transfer.php'],
],
Map: [
['Карта', '/map.php'],
['Добыча', '/map.php?st=mn'],
['Обработка', '/map.php?st=fc'],
['Производство', '/map.php?st=sh'],
['Дома', '/map.php?st=hs'],
],
Battles: [
['Битвы', '/bselect.php'],
['Протокол боев', `/pl_warlog.php?id=${MY_ID}`],
['Дуэли', '/one_to_one.php'],
['Групповые бои', '/group_wars.php'],
['Гильдия Тактиков', '/pvp_guild.php'],
['Гильдия Стражей', '/task_guild.php'],
['Гильдия Лидеров', '/leader_guild.php'],
['Гильдия Рейнджеров', '/ranger_list.php'],
['Бои за территории', '/mapwars.php'],
['Турниры', '/tournaments.php'],
],
Tavern: [
['Таверна', '/tavern.php'],
['Протокол игр', `/pl_cardlog.php?id=${MY_ID}`],
['Создать заявку', '/tavern.php?form=1'],
],
Roulette: [
['Рулетка', '/roulette.php'],
['Прошлая игра', '/inforoul.php'],
['История игр', '/allroul.php'],
['Редкие ларцы', '/gift_box_log.php'],
],
Rate: [
['Рейтинги', '/plstats.php'],
['Личные достижения ГО', `/pl_hunter_stat.php?id=${MY_ID}`],
['Рейтинг боевых кланов', '/clanstat.php'],
['Рейтинг охотников', '/plstats_hunters.php'],
['Рейтинг наемников', '/plstats_merc.php'],
['Рейтинг акционеров', '/sholders_stat.php'],
],
Forum: [
['Форум', '/forum.php'],
['Официальный', '/forum_thread.php?id=1'],
['Общий игровой', '/forum_thread.php?id=2'],
['Вопросы и помощь', '/forum_thread.php?id=10'],
['Идеи и предложения', '/forum_thread.php?id=3'],
['Об игре', '/ob-igre'],
]
};
function renderMenu([id, data]) {
const [name, href] = data.shift();
const image = `https://dcdn.heroeswm.ru/i/new_top/_panel${id}.png`;
return /*html*/`
<div class="menu" id="menu-${id}">
<a class="menu__link" href="${href}">
<img class="menu__icon" src="${image}">
</a>
<div class="menu__list" data-name="${name}">
${renderSubLinks(data)}
</div>
</div>
`;
}
function renderSubLinks(data) {
return data.map(([name, href]) => {
return `<a class="menu__item" href="${href}">${name}</a>`;
}).join('');
}
const html = Object.entries(navData).map(renderMenu).join('');
return `<nav id="hwm-nav">${html}</nav>`;
}
function renderPlayer(name) {
return /*html*/`
<header id="player">
<div>
<a href="/pl_info.php?id=${MY_ID}" id="player__name">${name}</a>
</div>
<div>
<span id="coin" class="coin">$</span>
<span id="player__gold" class="gold"></span>
</div>
</header>
`;
}
function renderForm() {
const inputHint = 'Шаг с зажатой клавишей:\nShift: 10\nCtrl: 100\nAlt: 1000';
return /*html*/`
<section id="form" class="__minimized">
<header>Лотов показано:</header>
<div id="form__lot" class="lot"></div>
<footer>
<label>
Кол-во
<input id="form__input" type="number" autocomplete="off" title="${inputHint}">
</label>
<button id="form__submit"><span>Купить лот</span></button>
</footer>
</section>
`;
}
function renderFilters({filters}) {
const len = Object.keys(filters).filter((k) => filters[k] !== null).length;
const data = {
once: ['Продажа', 'Торги'],
full: ['Целые', 'Слом'],
type: ['Сетовые', 'Не сетовые'],
craft: ['С крафтом', 'Без крафта'],
};
const icon = /*html*/`
<svg id="filters-icon" viewBox="0 0 16.5 17" width="18" height="18">
<path d="M175.051,8.283V.478a.478.478,0,1,0-.955,0v7.8a2.425,2.425,0,0,0,0,4.755v3.474a.478.478,0,1,0,.955,0V13.038a2.425,2.425,0,0,0,0-4.755Zm-.478,3.846a1.468,1.468,0,1,1,1.468-1.468A1.469,1.469,0,0,1,174.574,12.129Z" transform="translate(-166.302 0)"></path>
<path d="M9.751,4.278V.478a.478.478,0,0,0-.955,0v3.8a2.425,2.425,0,0,0,0,4.755v7.479a.478.478,0,0,0,.955,0V9.029a2.423,2.423,0,0,0,0-4.752ZM9.274,8.123a1.468,1.468,0,1,1,1.468-1.468A1.469,1.469,0,0,1,9.274,8.123Z" transform="translate(-6.85 0)"></path>
<path d="M339.351,4.278V.478a.478.478,0,0,0-.955,0v3.8a2.425,2.425,0,0,0,0,4.755v7.483a.478.478,0,0,0,.955,0V9.029a2.423,2.423,0,0,0,0-4.752Zm-.478,3.846a1.468,1.468,0,1,1,1.468-1.468A1.469,1.469,0,0,1,338.874,8.123Z" transform="translate(-324.789 0)"></path>
</svg>
`;
const active = (key, val) => filters[key] === val ? ' __active' : '';
const innerHTML = Object.keys(data).map((key) => {
const [one, two] = data[key];
return /*html*/`
<div class="filters__group">
<div class="filters__item${active(key, 1)}" data-filter="${key}=1">${one}</div>
<div class="filters__item${active(key, 0)}" data-filter="${key}=0">${two}</div>
</div>
`;
}).join('');
return /*html*/`
<div id="filters-box" class="a-box">
<button id="filters-remove" class="action">×</button>
<button id="filters-btn" class="a-btn __left">${icon}Фильтры</button>
<div id="filters" class="ui-scroll a-list">${innerHTML}</div>
<span id="filters-counter">${len}</span>
</div>
`;
}
function renderSorters({sort, order}) {
const headers = {
name: 'Товар',
type: 'Ставка',
cost: 'Цена/шт.',
time: 'Время',
owner: 'Владелец',
};
const innerHTML = Object.keys(headers).map((key) => {
const type = `by${key[0].toUpperCase() + key.slice(1)}`;
const attrs = [
`class="a-td sorts__item _${key}"`,
`data-sort="${type}"`,
];
if (type === sort) attrs.push(`data-order="${order}"`);
return `<span ${attrs.join(' ')}>${headers[key]}</span>`;
}).join('');
return `<div id="sorts">${innerHTML}</div>`;
}
function renderFaves(len) {
const extraInputAttrs = [
'type="text"',
'placeholder="Название закладки"',
'spellcheck="false"',
'autocomplete="off"',
].join(' ');
const btnClassName = `a-btn __left${len ? '' : ' __none'}`;
return /*html*/`
<div id="faves-box" class="a-box">
<button id="faves-toggle" class="action">+</button>
<button id="faves-btn" class="${btnClassName}">Избранное</button>
<div id="faves" class="ui-scroll a-list"></div>
<div id="faves-input-box">
<input id="faves-input" class="a-input __left" ${extraInputAttrs}>
<button id="faves-add" class="action">OK</button>
</div>
</div>
`;
}
// ====================
$('#hwm-nav', aucElem).addEventListener('mouseover', (e) => {
const trg = e.target;
if (!trg.matches('.menu__item')) return;
trg.addEventListener('mousemove', move);
trg.addEventListener('mouseleave', function leave(e) {
this.removeEventListener('mousemove', move);
this.removeEventListener(e.type, leave);
});
function move(e) {
this.setAttribute('style', `--x: ${~~e.layerX}px; --y: ${~~e.layerY}px`);
}
});
// ====================
const newSetArtsData = userData.newSetArts;
Object.entries(newSetArtsData).forEach(([name, data]) => {
if (!allSetData[name]) return allSetData[name] = data;
const arts = allSetData[name].arts;
data.arts.forEach(art => arts.includes(art) || arts.push(art));
});
const allSetArts = Object.values(allSetData).map(that => that.arts).flat(1);
const allSetArtsRus = {};
// ====================
const setLoadState = aucClassList.toggle.bind(aucClassList, '__loading');
const setSortsPad = ((target, sortStyle) => {
return () => {
sortStyle.paddingRight = `${target.offsetWidth - target.clientWidth}px`;
};
})($('#lots-container', aucElem), $('#sorts', aucElem).style);
const aucHwmForm = ((target) => {
return {
get target() {
return target;
},
get name() {
return target.name;
},
replace(newForm) {
target.replaceWith(newForm);
return (target = newForm);
}
};
})(document.createElement('form'));
// ====================
if (document.readyState === 'loading') {
await new Promise(resolve => {
view.addEventListener('load', resolve, { once: true });
document.addEventListener('DOMContentLoaded', resolve, { once: true });
});
}
insertContainer();
// ====================
let isOnLine = true;
let searchParams = getSearchParams(location.search);
function goTo(search) {
if (location.search !== search) {
history.pushState(null, '', AUC_PATH + search);
}
return loadPage(search);
}
async function loadPage(search = location.search) {
searchParams = getSearchParams(search);
setLoadState(1);
timers.clear();
activeLot && form.minimize(true);
const hwm_elem = await getHWMElem(getAucURL(search));
if (!hwm_elem) return;
const {cat} = searchParams;
const key = searchParams[cat === 'res' ? 'type' : 'art_type'];
aucClassList.remove('__unallowed', '__disconnected');
bets.shown && bets.hide();
const stuffCats = ['res', 'elements', 'part', 'dom', 'cert', 'obj_share'];
filters.partial(stuffCats.includes(cat));
filters.disable(['my', 'obj_share'].includes(cat));
extraStyle.__replace(0, /cat-\S+/, `cat-${cat}`);
extraStyle.__replace(0, /type=[^"]+/, `type=${key}`);
lotsBox.load(hwm_elem);
timers.switchTimers();
setLoadState(0);
if (cat === 'my') resources.updateFromServer();
}
async function getHWMElem(url) {
const doc = await fetch.get(url).catch(() => ({ URL: '' }));
if (!doc.URL.includes(AUC_PATH)) return setNoAccess();
const selector = 'td.wbwhite tbody';
const hwm_elem = attempt($(selector, doc), importNode);
if (!hwm_elem) {
const msg = [
'Невозможно построить список лотов.',
`Элемент с селектором "${selector}" отсутствует в оригинальном DOM.`,
].join('\n');
return Alert.error(msg, { isFinite: false });
}
while (true) {
const elem = hwm_elem.firstElementChild;
if (!elem || elem.className) return hwm_elem;
elem.remove();
}
}
const setNoAccess = throttle(() => {
setLoadState(0);
form.disable(false);
aucClassList.add('__unallowed');
Alert.error('В данный момент рынок не доступен!', { isFinite: false });
if (!isOnLine) return aucClassList.add('__disconnected');
const isAuthorized = () => document.cookie.includes(`pl_id=${MY_ID}`);
if (isAuthorized()) return;
Alert.error('Вы деавторизованы!', {
isFinite: false,
onCreate(that) {
this.timerId = setTimeout(() => {
return isAuthorized() ? that.destroy() : this.onCreate(that);
}, 2e3);
},
onDestroy() {
clearTimeout(this.timerId);
if (!isAuthorized()) return setTimeout(() => location.replace('/'));
aucClassList.remove('__unallowed');
Alert.ok('Вы снова авторизованы');
}
});
}, 500);
// ====================
const allLots = [];
function findLot(key, value, lots = allLots) {
return lots.find(lot => lot[key] === value);
}
function filterLots(lots = allLots) {
if (bets.shown || searchParams.cat === 'my') return lots;
const {filters} = userData;
const keys = Object.keys(filters);
return lots.filter(lot => {
if (lot.cat === 'obj_share') return true;
if (lot.classType !== 'Art') {
return [null, +lot.once].includes(filters.once);
}
return keys.every(key => {
const val = filters[key];
if (val === null) return true;
switch (key) {
case 'once': return +lot.once === val;
case 'full': return +Object.is(...lot.durability) === val;
case 'type': return +lot.fromSet === val;
case 'craft': return !lot.mods === !val;
}
});
});
}
// ==================== [[ LOT TYPES ]]
let activeLot = null;
class Lot {
constructor() {
Object.assign(this, createLotData(...arguments));
}
get classType() {
return this.constructor.name;
}
get isActive() {
return this === activeLot;
}
get search() {
return `?cat=${this.cat}`;
}
select() {
if (!this.once && this.owner[1] === MY_ID) return;
if (this.isActive) return form.minimize(true);
if (activeLot) {
activeLot.target.classList.remove('__active');
}
this.target.classList.add('__active');
form.refreshByLot(activeLot = this);
}
increaseBetAmount() {
const elem = $('.lot__bet-amount', this.target);
elem.textContent = ++this.betAmount;
}
refresh() {
const {target} = this;
const curFormVal = +form.inputValue;
if (this.once) {
this.amount -= curFormVal;
this.amount <= 0 && this.complete();
player.refreshGold(this.cost * curFormVal);
} else {
this.myBet = curFormVal;
this.cost = form.getMinBet(this.cost);
this.lastHero = [player.name, MY_ID];
player.refreshGold(curFormVal);
if (this.blitz && curFormVal >= this.blitz) this.complete();
else target.dataset.params += '&mybet=1';
}
target.innerHTML = createLot(this).innerHTML;
}
expire() {
this.complete(true);
}
complete(force) {
const {target} = this;
this.completed = true;
target.dataset.params += '&completed=1';
if (force) target.style.setProperty('--timer', '00:00');
if (this.isActive) form.minimize(true);
}
async reload() {
if (this.completed || !this.target.offsetWidth) return;
const processingEl = parseNode(/*html*/`
<div class="lot__processing">
<span class="lot__loading">Загрузка</span>
</div>
`);
this.target.prepend(processingEl);
const hwm_form = await this.getRemoteHwmForm();
if (hwm_form === 0) return;
if (!hwm_form) {
this.complete(Date.now() >= this.time[1]);
processingEl.innerHTML = '<span>Торги закончены</span>';
return setTimeout(() => processingEl.remove(), 2e3);
}
this.hardRefresh(hwm_form.closest('tr.wb'));
if (this.isActive) form.refreshByLot(this, ~~form.inputValue);
timers.switchTimers();
}
async getRemoteHwmForm() {
const url = getAucURL(this.search);
const doc = await fetch.get(url).catch(() => ({ URL: '' }));
if (!doc.URL.includes(AUC_PATH)) {
setNoAccess();
return 0;
}
return $(`form[name$="${this.id}"]`, doc);
}
hardRefresh(hwm_elem) {
const that = createNewLot(hwm_elem, this.cat, this.constructor);
const keys = ['amount', 'betAmount', 'cost', 'time', 'lastHero'];
keys.forEach(key => {
if (that.hasOwnProperty(key)) this[key] = that[key];
});
this.target.innerHTML = that.target.innerHTML;
this.target.dataset.params = that.target.dataset.params;
}
}
class Res extends Lot {
get search() {
return `?cat=${this.cat}&type=${this.key}`;
}
get key() {
return 1 + Res.TYPES.indexOf(this.resName);
}
get resName() {
return this.image.match(/\w+(?=\.png)/)[0];
}
}
Res.TYPES = ['wood', 'ore', 'mercury', 'sulfur', 'crystals', 'gems'];
class GnElem extends Lot {
get search() {
return `?cat=${this.cat}&art_type=${this.key}`;
}
get key() {
return this.image.match(/\w+(?=\.png)/)[0];
}
}
class Art extends Lot {
constructor(hwm_elem) {
super(...arguments);
const {firstElementChild: elem} = hwm_elem;
const {search} = $('a[href^="art_info"]', elem);
const key = search.match(/=([^&]+)/)[1];
Object.assign(this, {
key,
mods: Art.getMods(elem),
durability: Art.getDurability(elem),
fromSet: allSetArts.includes(key),
});
}
get search() {
return `?cat=${this.cat}&art_type=${this.key}`;
}
static get modColors() {
return {
A: '#ab91c7',
D: '#a09f9f',
E: '#ac6262',
F: '#ff8f1b',
I: '#d2b48c',
N: '#73ac6c',
W: '#74b4f6'
};
}
static getMods(elem) {
const match = elem.textContent.match(/\[([IEAWFDN\d]{2,})\]/);
return match && match[1].match(/[A-Z]\d+/g);
}
static createModsHTML(mods) {
const colors = this.modColors;
return mods.map((mod) => {
return `<font color="${colors[mod[0]]}">${mod}</font>`;
}).join(' ');
}
static createModImgsHTML(mods) {
const path = 'https://dcdn3.heroeswm.ru/i/mods_png';
return mods.map((mod) => `<img src="${path}/${mod}.png">`).join('');
}
static getDurability(elem) {
const html = elem.innerHTML;
const match = elem.textContent.match(/\d+\/\d+/)[0];
const values = match.split('/').map(Number);
const isMaxRed = html.includes('font>/<font');
const type = isMaxRed ? 2 : +html.includes('Прочность: <font');
return [...values, type];
}
}
class ArtPart extends Lot {
constructor(hwm_elem) {
super(...arguments);
const {search} = $('a[href^="art_info"]', hwm_elem.firstElementChild);
this.key = search.match(/=(\w+)/)[1];
}
get search() {
return `?cat=${this.cat}&art_type=part_${this.key}`;
}
}
class Cert extends Lot {
constructor(hwm_elem) {
super(...arguments);
const {data} = $('b', hwm_elem.firstElementChild).previousSibling;
this[this.cat] = { html: `<p class="place">${data.trim()}</p>` };
}
}
class Share extends Lot {
constructor(hwm_elem) {
super(...arguments);
this[this.cat] = Share.getShare(hwm_elem.firstElementChild);
}
static getShare(elem) {
const link = $('[href^="object-info"]', elem);
const place = $('[href^="map.php"]', elem).outerHTML.replace('pi', 'place');
const match = (elem.textContent.match(/,\s([^[]+)/) || ' ')[1].trim();
const details = match.replace(/(\d+)/, '$1<br>');
return {
link: link.outerHTML.replace('<a', ' <a class="obj-id"'),
html: `<p class="obj-details">${details}</p><p class="place">${place}</p>`
};
}
}
class House extends Lot {
constructor(hwm_elem) {
super(...arguments);
this[this.cat] = House.getHouse(hwm_elem.firstElementChild);
}
static getHouse(elem) {
const link = $('[href^="house_info"]', elem);
const place = $('b', elem).previousSibling.data.trim();
const points = ['star_outline', 'star', 'star_half'];
const hwm_stars = elem.innerHTML.match(/\/star\d+/g).map(x => [...x].pop());
const stars = hwm_stars.map(x => {
return `<span class="house__star m-icon">${points[x]}</span>`;
}).join('');
return {
link: link.outerHTML.replace('<a', ' <a class="obj-id"'),
html: `<p class="place">${place}</p><p class="house__stars">${stars}</p>`
};
}
}
// ====================
function createLotData(elem, cat) {
const {common} = createLot;
const {children} = elem;
const {innerHTML} = children[0];
const once = children[1].childElementCount === 1;
const image = $('img:last-of-type', children[0]).src;
const reg = /_protocol.+?id=([^&'"]+).+?crc=([^&'"]+).+?- ([^\[&<]+)/;
const matches = innerHTML.match(reg);
const that = {
id: matches[1],
crc: matches[2],
name: matches[3].trim(),
cat,
image,
once,
amount: +!once || +innerHTML.match(/\d+(?= шт\.)/) || 1,
cost: common.getCost(elem),
time: common.getTime(children[3]),
owner: common.getHero(children[4]),
};
return once ? that : Object.assign(that, common.getBet(children[1]));
}
function createNewLot(hwm_elem, category, constructor) {
if (category === 'my') {
const image = $('img:last-of-type', hwm_elem).src;
category = getCatByImage(image) || category;
}
const Entity = constructor || getClassByCategory(category);
const lot = new Entity(hwm_elem, category);
lot.target = createLot(lot);
return lot;
}
function getCatByImage(image) {
if (image.includes('/r/48/')) return 'res';
if (image.includes('/gn_res/')) return 'elements';
if (image.includes('/auc_dom')) return 'dom';
if (image.includes('/house_cert')) return 'cert';
if (image.includes('/obj_share')) return 'obj_share';
if (image.includes('/parts/')) return 'part';
}
function getClassByCategory(cat) {
return {
res: Res,
elements: GnElem,
dom: House,
cert: Cert,
obj_share: Share,
part: ArtPart
}[cat] || Art;
}
function createLot(lot) {
const {common, layout} = createLot;
const {id, crc, cat} = lot;
const isArt = lot.classType === 'Art';
const isArtPart = cat === 'part';
const imgContTag = (isArt || isArtPart) ? 'a' : 'div';
const linkAttr = imgContTag === 'a'
? ` href="/art_info.php?id=${lot.key}"`
: '';
const mods = isArt ? lot.mods : null;
const dur = isArt
? layout.getDurability(lot.durability)
: isArtPart
? '1/100'
: '';
const timeHTML = `<span class="lot__time">${lot.time[0]}</span>`;
return parseNode(/*html*/`
<div class="lot" ${layout.getDataAttrs(lot)}>
<div class="a-td _name">
<${imgContTag} class="lot__box"${linkAttr}>
<img class="lot__img" src="${lot.image}">
${layout.getAmount(lot)}
${mods && `<span class="art-mods">${Art.createModImgsHTML(mods)}</span>` || ''}
</${imgContTag}>
<div class="lot__info">
<a class="lot__id" href="/auction_lot_protocol.php?id=${id}&crc=${crc}">${id}</a>
${layout.getName(lot)}
${lot[cat] && lot[cat].html || ''}
${mods && `<p class="mods-scope">${Art.createModsHTML(mods)}</p>` || ''}
${dur && `<p class="lot__durability">${dur}</p>`}
</div>
</div>
<div class="a-td _type">${layout.getBet(lot)}</div>
${renderLotCost(lot)}
<div class="a-td _time">${timeHTML}</div>
<div class="a-td _owner">${layout.getHero(lot.owner)}</div>
</div>
`);
}
function renderLotCost(lot) {
return /*html*/`
<div class="a-td _cost">
<div>
<span class="gold">${formatNum(lot.cost)}</span>
<span class="coin">$</span>
</div>
${lot.lastHero ? createLot.layout.getHero(lot.lastHero) : ''}
${lot.myBet ? `<p class="mybet">${formatNum(lot.myBet)}</p>` : ''}
</div>
`;
}
createLot.common = {
timeData: {
'д': v => v * 86400,
'ч': v => v * 3600,
'мин': v => v * 60,
'с': v => ~~v
},
getTime(elem) {
const value = elem.textContent;
const parts = value.match(/\d+ (д|ч|мин|с)/g);
const sec = !parts ? 0 : parts.reduce((a, b) => {
const data = b.split(' ');
return a + this.timeData[data[1]](data[0]);
}, 0);
return [value, Date.now() + sec * 1e3];
},
getBet(elem) {
const that = {};
const amount = that.betAmount = elem.firstChild.data >> 0;
if (amount) that.lastHero = this.getHero(elem.nextElementSibling, that);
const last = elem.lastElementChild;
if (last) that.blitz = parseNum(last.textContent);
return that;
},
getCost(elem) {
const value = $('[id^=au] td:last-child', elem).textContent;
return parseNum(value);
},
getHero(elem, that) {
const link = $('[href^="pl_info"]', elem) || {};
const name = link.textContent || '';
const bet = that && ((link.nextSibling || {}).data || '').slice(2);
if (bet) that.myBet = +bet;
else if (that) delete that.myBet;
return [name, link.search.slice(4)];
},
};
createLot.layout = {
getDataAttrs(data) {
const {cat} = data;
const isArt = data.hasOwnProperty('key');
const keyStr = isArt ? ` data-key="${data.key}"` : '';
const params = [`once=${+data.once}`];
const hero = (data.lastHero || '')[0];
if (data.owner[1] === MY_ID) params.push('mylot=1');
if (hero === player.name) params.push('mybet=1');
const paramsStr = cat === 'obj_share'
? ' data-params'
: ` data-params="${params.join('&')}"`;
return `data-id="${data.id}" data-cat="${cat}"` + keyStr + paramsStr;
},
getBet({id, once, blitz, betAmount}) {
if (once) return '<span class="lot__bet-type">Купить сразу</span>';
const html = `<span class="lot__bet-amount">${betAmount}</span>`;
const watchHTML = bets.has(id) ? bets.createIconTpl() : '';
const blitzHTML = !blitz ? '': /*html*/`
<p class="lot__bet-type">Блиц цена:</p>
<p class="lot__blitz">
<span class="gold">${formatNum(blitz)}</span>
<span class="coin">$</span>
</p>
`;
return watchHTML + html + blitzHTML;
},
getAmount({amount, cat}) {
return (amount > 1 || ['res', 'elements'].includes(cat))
? `<span class="lot__amount">${amount}</span>`
: '';
},
getName(data) {
const {name, cat, fromSet} = data;
const html = `<p class="lot__name">${name}</p>`;
if (fromSet) return html.replace('name', 'name c-set');
const link = data[cat] ? data[cat].link : '';
return link ? html.replace('</', ` ${link}</`) : html;
},
getHero([name, id]) {
return `<a href="/pl_info.php?id=${id}">${name}</a>`;
},
getDurability(arr) {
if (!arr[2]) return arr.slice(0, 2).join('/');
const colorize = (n) => `<font color="lightcoral">${n}</font>`;
return arr[2] === 1
? `${colorize(arr[0])}/${arr[1]}`
: arr.slice(0, 2).map(colorize).join('/');
}
};
// ====================
const lotsBox = ((target) => {
let hoveredElem = null;
return {
__init__() {
target.addEventListener('click', ({target: trg}) => {
const elem = trg.tagName === 'A' ? null : trg.closest('.lot');
const lot = elem && findLot('target', elem);
if (!lot) return;
lot.select();
setSortsPad();
});
target.addEventListener('mouseover', ({target: trg}) => {
if (trg.hasAttribute('data-id')) hoveredElem = trg;
});
target.addEventListener('mouseleave', () => (hoveredElem = null));
},
target: target,
load({children}) {
const {cat} = searchParams;
const lots = [...children].map(el => createNewLot(el, cat));
allLots.splice(0, Infinity, ...lots);
sort[userData.sort]();
this.appendAll(filterLots());
},
appendAll(lots) {
target.replaceChildren(...lots.map(lot => lot.target));
setSortsPad();
},
get selectedLot() {
return hoveredElem && findLot('target', hoveredElem);
}
};
})($('#lots'));
const timers = (() => {
let timerId = 0;
const format = (n) => n > 9 ? n : `0${n}`;
const stringify = (t) => `'${format(t / 60 >> 0)}:${format(t % 60)}'`;
function loop() {
const now = Date.now();
allLots.forEach(lot => {
if (lot.completed) return;
const endTime = lot.time[1];
const sec = now >= endTime ? 0 : (endTime - now) / 1e3 >> 0;
if (!sec) return lot.expire();
if (sec > 180 || !lot.target.offsetWidth) return;
const value = stringify(sec);
lot.target.style.setProperty('--timer', value);
lot.isActive && form.lotElem.style.setProperty('--timer', value);
});
timerId = setTimeout(loop, 1e3);
}
return {
switchTimers() {
this.clear();
loop();
},
clear() {
clearTimeout(timerId);
}
};
})();
const player = (() => {
const goldEl = $('#player__gold');
return {
__init__() {
if (this.name) return;
fetch.get(`/pl_info.php?id=${MY_ID}`).then(({title}) => {
const name = title.split('|')[0].trim();
$('#player__name').textContent = name;
userData.update('playerName', name);
extraStyle.__replace(1, 'NAME', name);
});
},
refreshGold(n) {
goldEl.textContent = formatNum(resources.refresh('gold', -n));
},
get id() {
return MY_ID;
},
get name() {
return userData.playerName;
},
get gold() {
return resources.gold;
}
};
})();
const resources = ((target) => {
const elemsData = { gold: document.head };
const hwmSelector = '#ResourcesPanel, #top_res_table, #panel_resourses';
function getElems(context = document, selector = hwmSelector) {
const container = $(selector, context);
return container ? $$('img', container).slice(0, 7).map(create) : [];
}
function create(img, i) {
const href = !i ? '#' : `${AUC_PATH}?cat=res&type=${i}`;
return parseNode(/*html*/`
<span class="resources__item" data-value="${getValue(img)}">
<a href="${href}"><img src="${img.src}" width="24"></a>
</span>
`, el => (el.__key = img.src.match(/\w+(?=\.png)/)[0]));
}
function getValue(img) {
const node = img.nextElementSibling || img.parentNode.nextSibling;
return node.textContent.trim();
}
return {
__init__() {
const newHeader = (modules.get('HWM_new_header') || {}).exports;
if (!newHeader) return this.update();
this.update(newHeader, '.header-resources');
},
get gold() {
return parseNum(elemsData.gold.dataset.value);
},
update() {
const elems = getElems(...arguments);
const data = Object.fromEntries(elems.map(el => [el.__key, el]));
Object.assign(elemsData, data);
target.replaceChildren(...elems);
player.refreshGold(0);
},
async updateFromServer() {
const url = '/transfer.php';
const context = await fetch.get(url).catch(() => ({ URL: '' }));
if (!context.URL.includes(url)) return setNoAccess();
this.update(context);
},
refresh(key, n) {
return ~~attempt(elemsData[key], ({dataset}) => {
const value = n + parseNum(dataset.value);
dataset.value = formatNum(value);
return value;
});
}
};
})($('#resources'));
const artsSelect = ((target) => {
const newArts = [];
const setArts = [];
const newArtsData = userData.newArts;
function initOptions(hwm_select) {
const selectItem = parseNode('<a class="a-link a-list__item"></a>');
const hwm_options = [...hwm_select.options].slice(1);
hwm_options.forEach(({value, textContent}) => {
const item = selectItem.cloneNode();
const [cat, id] = value.split('#');
item.textContent = textContent;
item.setAttribute('href', `${AUC_PATH}?cat=${cat}&art_type=${id}`);
if (allSetArts.includes(id)) {
item.className += ' c-set';
allSetArtsRus[id] = textContent;
}
if (!allArtsData[id]) newArts.push(id);
target.appendChild(item);
});
}
async function pullArtsFromServer() {
const addArt = (id, value) => {
allArtsData[id] = newArtsData[id] = value;
};
const addSetArt = (link, id) => {
const name = link.hash.slice(1);
if (!newSetArtsData[name]) {
newSetArtsData[name] = {
rus: link.textContent.replaceAll('"', ''),
arts: [id]
};
} else if (!newSetArtsData[name].arts.includes(id)) {
newSetArtsData[name].arts.push(id);
}
};
const handleArt = async (id) => {
const ctx = await fetch.get(`/art_info.php?id=${id}`);
const img = $('.arts_info img[src*="/artifacts/"]', ctx);
if (!img) return;
const setLinks = $$('.s_art_inside a[href*="?section=40#"]', ctx);
setLinks.forEach(link => addSetArt(link, id));
let value = img.src.split('/artifacts/')[1].replace('_b.png', '');
if (value === id) return addArt(id, '&');
if (!value.includes('/')) return addArt(id, value);
const parts = value.split('/');
value = parts.pop();
addArt(id, `${parts.join('/')}/${value === id ? '&' : value}`);
};
while (newArts.length) {
let promises = newArts.splice(0, 5).map(handleArt);
await Promise.all(promises);
}
}
return {
__init__() {
Object.assign(allArtsData, newArtsData);
const eye = $('#artlist-eye');
eye.addEventListener('click', () => {
if (eye.classList.toggle('__switched-on')) {
this.arts.forEach(addImageToArt);
} else {
$$('.a-link[style]', target).forEach(el => {
el.removeAttribute('style');
});
}
});
initOptions($('select[name="ss2"]'));
if (!newArts.length) return;
const msg = 'Список лотов обновлен. Добавлено: ' + newArts.length;
Alert.addStartMessage(msg);
pullArtsFromServer().then(() => userData.update()).catch(setNoAccess);
},
get arts() {
return [...target.children];
},
get setArts() {
if (setArts.length) return setArts;
setArts.push(...this.arts.filter(el => el.matches('.c-set')));
return setArts;
},
get hasImages() {
return !!$('.a-link[style]', target);
}
};
})($('#artlist'));
const setArtsSelect = ((target) => {
return {
__init__() {
Object.keys(allSetData).forEach(this.addContainer);
target.addEventListener('click', ({target: trg}) => {
if (!trg.matches('.setlist__set-name')) return;
const parent = trg.parentNode;
parent.classList.toggle('__active');
if (parent.childElementCount === 1) {
parent.appendChild(this.createList(parent.dataset.set));
}
});
},
addContainer(name) {
return target.appendChild(parseNode(/*html*/`
<div class="setlist__set" data-set="${name}">
<h4 class="setlist__set-name c-set">${allSetData[name].rus}</h4>
</div>
`));
},
createList(name) {
const container = parseNode('<div class="setlist__arts"></div>');
container.append(...this.getArts(name));
return container;
},
getArts(name) {
const {setArts} = artsSelect;
return allSetData[name].arts.map(key => {
const rus = allSetArtsRus[key];
const elem = rus && setArts.find(art => art.textContent === rus);
if (!elem) return;
const art = elem.cloneNode(true);
art.classList.remove('c-set');
if (!art.hasAttribute('style')) addImageToArt(art);
return art;
}).filter(Boolean);
}
};
})($('#setlist'));
const categories = ((target) => {
const subLayouts = {};
function onHandleClick({target: trg}) {
if (!trg.matches('.category__heading')) return;
const parent = trg.parentNode;
const menu = trg.nextElementSibling;
const test = !!menu.childElementCount;
const id = parent.id.slice(4);
if (!test) menu.innerHTML = createListHTML(id);
if (!parent.classList.toggle('__active')) menu.removeAttribute('style');
else menu.style.setProperty('--count', menu.childElementCount);
if (test) return;
if (this.isArtsCategory(id)) this.colorizeSetArts(menu);
else if (id === 'elements') addImgToElements(menu);
}
function createListHTML(id) {
const html = id === 'res'
? subLayouts[id]
: extractSubLayout(subLayouts[id]);
return html.replace(/&sort=\d/g, '');
}
function extractSubLayout(text) {
return text
.match(/<a[^']+/)[0]
.replace(/ |<\/?[b-z].*?>/gi, '')
.replaceAll('href=', 'class="category__item" href=');
}
function addImgToElements(elem) {
[...elem.children].forEach(el => {
const id = el.search.split('=').pop();
el.style.backgroundImage = `url(/i/gn_res/${id}.png)`;
});
}
function getResourcesHTML(elem) {
return [...elem.children]
.filter(el => el.tagName === 'A' && el.search.includes('&type'))
.map(link => {
const {src, title} = link.firstElementChild;
const attrs = [
'class="category__item"',
`href="${AUC_PATH + link.search}"`,
`style="background-image: url(${src})"`,
];
return `<a ${attrs.join(' ')}>${title}</a>`;
}).join('');
}
return {
__init__() {
let layout = '';
const hwmElem = $('td.wblight[valign]');
const hwm_elems = $$('[id^="mark_"]:not([id*="_info_"])', hwmElem);
subLayouts.res = getResourcesHTML(hwmElem);
attempt($('a[href*="?cat=my&"]', hwmElem), el => {
const len = (el.textContent.match(/\d/) || '')[0];
if (!len) return;
layout += this.createCategoryTemplate({
id: 'my',
name: 'Ваши товары',
test: true,
len
});
});
layout += this.createCategoryTemplate({
id: 'res',
name: 'Ресурсы',
len: hwmElem.firstElementChild.textContent.slice(9, -1)
});
hwm_elems.forEach(el => {
const id = el.id.slice(5);
const first = el.firstElementChild;
const name = first.textContent;
const len = (el.textContent.match(/\((\d+)/) || ['', ''])[1];
const test = el.childElementCount === 2;
const script = el.nextElementSibling.nextElementSibling;
subLayouts[id] = script.textContent;
layout += this.createCategoryTemplate({id, name, len, test});
});
if (!$('a[href="auction_new_lot.php"]', hwmElem)) {
$('#new-lot').textContent = 'Рынок не построен';
}
target.addEventListener('click', onHandleClick.bind(this));
hwmElem.remove();
target.innerHTML = layout;
attempt($('#cat-res', target), el1 => {
attempt($('#cat-elements', target), el2 => el1.after(el2));
});
},
isArtsCategory(id) {
const reg = /(?:share|cert|dom|elements|res)$/;
return !reg.test(id);
},
createCategoryTemplate({id, name, len, test}) {
let attrsRaw = 'class="category__all"';
if (test) attrsRaw += ` href="${AUC_PATH}?cat=${id}"`;
const tag = test ? 'a' : 'span';
const all = len && `<${tag} ${attrsRaw}>${len}</${tag}> `;
return /*html*/`
<div class="category" id="cat-${id}">
<h4 class="category__heading">${all + name}</h4>
<div class="category__items"></div>
</div>
`;
},
colorizeSetArts(elem) {
[...elem.children].forEach(el => {
const id = el.search.split('=').pop();
allSetArts.includes(id) && el.classList.add('c-set');
addImageToArt(el);
});
}
};
})($('#categories'));
const search = ((target) => {
let selectedElem = null;
const listElem = target.nextElementSibling;
const searchTypeBtn = listElem.nextElementSibling;
const resetBtn = searchTypeBtn.nextElementSibling;
const letters = {
"`": "ё",
"q": "й",
"w": "ц",
"e": "у",
"r": "к",
"t": "е",
"y": "н",
"u": "г",
"i": "ш",
"o": "щ",
"p": "з",
"[": "х",
"]": "ъ",
"a": "ф",
"s": "ы",
"d": "в",
"f": "а",
"g": "п",
"h": "р",
"j": "о",
"k": "л",
"l": "д",
";": "ж",
"'": "э",
"z": "я",
"x": "ч",
"c": "с",
"v": "м",
"b": "и",
"n": "т",
"m": "ь",
",": "б",
".": "ю",
};
if (!('scrollIntoViewIfNeeded' in Element.prototype)) {
const proto = Element.prototype;
proto.scrollIntoViewIfNeeded = proto.scrollIntoView;
}
function selectSibling(isDirNext) {
if (!selectedElem) {
const prop = isDirNext ? 'lastElementChild' : 'firstElementChild';
selectedElem = listElem[prop];
}
const sibling = getSibling(isDirNext);
selectedElem.removeAttribute('id');
selectedElem = sibling;
sibling.id = 'select-link';
sibling.scrollIntoViewIfNeeded(false);
target.value = sibling.textContent;
}
function getSibling(isDirNext) {
return isDirNext
? selectedElem.nextElementSibling || listElem.firstElementChild
: selectedElem.previousElementSibling || listElem.lastElementChild;
}
function getElemes(val) {
val = [...val].map(x => letters[x] || x).join('');
const method = ['startsWith', 'includes'][+userData.extSearch];
const lower = str => str.toLowerCase();
return artsSelect.arts.filter(el => lower(el.textContent)[method](val));
}
function render() {
const val = target.value.trim();
resetBtn.classList.toggle('__shown', !!val);
listElem.innerHTML = '';
selectedElem = null;
val && this.fill(val.toLowerCase());
}
return {
__init__() {
render = render.bind(this);
searchTypeBtn.addEventListener('click', () => {
userData.update(
'extSearch',
searchTypeBtn.classList.toggle('__active')
);
if (target.value) render();
});
resetBtn.addEventListener('click', () => {
this.clear();
target.focus();
});
target.addEventListener('wheel', (e) => {
if (!listElem.childElementCount) return;
selectSibling(e.deltaY > 0);
});
target.addEventListener('keydown', (e) => {
if (e.altKey && e.code === 'KeyS') {
e.preventDefault();
e.stopPropagation();
searchTypeBtn.click();
return target.focus();
}
const allowedKeys = ['ArrowDown', 'ArrowUp', 'Escape', 'Enter'];
const index = allowedKeys.indexOf(e.key);
if (!~index) return;
if (index === 2) return resetBtn.click();
e.stopPropagation();
if (index < 2) {
if (!listElem.childElementCount) return;
e.preventDefault();
selectSibling(!index);
return;
}
if (selectedElem) {
selectedElem.click();
resetBtn.click();
}
});
target.addEventListener('input', debounce(render, 400));
},
fill(val) {
const elems = getElemes(val);
const isImgNeeded = !(elems.length && artsSelect.hasImages);
elems.forEach(el => {
el = el.cloneNode(true);
isImgNeeded && addImageToArt(el);
listElem.appendChild(el);
});
},
clear() {
resetBtn.classList.remove('__shown');
listElem.innerHTML = target.value = '';
selectedElem = null;
}
};
})($('#search'));
const faves = ((target) => {
const myFaves = userData.faves;
const [switcher, button, listElem] = target.children;
const inputElem = target.lastElementChild.firstElementChild;
const getLength = () => Object.keys(myFaves).length;
return {
__init__() {
target.addEventListener('click', (e) => {
const trg = e.target;
const action = trg.dataset.faveAction || trg.id.slice(6);
return this[action] && this[action](e);
});
inputElem.addEventListener('keydown', ({key}) => {
if (key === 'Enter') this.add();
else if (key === 'Escape') this.toggle();
});
if (!getLength()) return;
const entries = Object.entries(myFaves);
const items = entries.map(entry => this.create(...entry));
listElem.append(...items);
},
create(search, name) {
const href = AUC_PATH + search;
const item = parseNode(/*html*/`
<a class="a-link a-list__item fave-item" href="${href}">
${name}
<span data-fave-action="remove">×</span>
</a>
`);
const id = search.split('=').pop();
allSetArts.includes(id) && item.classList.add('c-set');
addImageToArt(item);
return item;
},
toggle() {
if (!switcher.classList.toggle('__active')) return;
attempt($(`a[href="${AUC_PATH + location.search}"]`), link => {
const text = link.matches('.category__all')
? link.nextSibling.data
: link.textContent.match(/[^(]+/)[0];
inputElem.value = text.trim();
inputElem.focus();
});
},
add() {
const {search} = location;
const name = inputElem.value.trim() || `лот #${getLength() + 1}`;
if (search in myFaves) {
return Alert.warn('Такой лот уже есть в списке!');
}
myFaves[search] = name;
userData.update();
listElem.append(this.create(search, name));
this.toggle();
button.classList.remove('__none');
},
remove(e) {
e.preventDefault();
e.stopPropagation();
const item = e.target.parentNode;
delete myFaves[item.search];
userData.update();
item.remove();
button.classList.toggle('__none', !getLength());
}
};
})($('#faves-box'));
const filters = ((target) => {
const filtersData = userData.filters;
const counterEl = $('#filters-counter');
const actives = target.getElementsByClassName('__active');
return {
__init__() {
target.addEventListener('click', ({target: trg}) => {
if (trg.id === 'filters-remove') return this.clear();
const params = trg.dataset.filter;
if (!params) return;
const [key, value] = params.split('=');
const isActive = trg.classList.toggle('__active');
filtersData[key] = isActive ? +value : null;
const nodes = [...trg.parentNode.children];
const sibling = nodes[nodes.indexOf(trg) ^ 1];
sibling.classList.remove('__active');
this.update();
});
},
partial(test) {
return target.classList.toggle('__partial', test);
},
disable(test) {
return target.classList.toggle('__disabled', test);
},
clear() {
[...actives].forEach(el => el.classList.remove('__active'));
for (const key in filtersData) filtersData[key] = null;
this.update();
},
update() {
userData.update();
form.minimize(true);
lotsBox.appendAll(filterLots());
counterEl.textContent = actives.length;
}
};
})($('#filters-box'));
const sort = ((target) => {
const compare = {
string: (a, b) => a < b ? -1 : +(a > b),
number: (a, b) => a - b,
};
return {
__init__() {
target.addEventListener('click', ({target: trg}) => {
const sortBy = trg.dataset.sort;
if (!sortBy) return;
[...target.children].forEach(el => {
el !== trg && el.removeAttribute('data-order');
});
lotsBox.target.dataset.order = (trg.dataset.order ^= 1);
userData.update('order', trg.dataset.order);
if (userData.sort === sortBy) return;
this[sortBy]();
userData.update('sort', sortBy);
lotsBox.appendAll(filterLots());
});
},
byName() {
allLots.sort((a, b) => compare.string(a.name, b.name));
},
byType() {
const get = (that) => that.once ? 1e3 : ~~that.betAmount;
allLots.sort((a, b) => compare.number(get(a), get(b)));
},
byCost() {
allLots.sort((a, b) => compare.number(a.cost, b.cost));
},
byTime() {
allLots.sort((a, b) => compare.number(a.time[1], b.time[1]));
},
byOwner() {
const get = (that) => that.owner[0].toLowerCase();
allLots.sort((a, b) => compare.string(get(a), get(b)));
}
};
})($('#sorts'));
const artInfo = ((target) => {
let isVisible = false;
const cache = {};
const artKeyPropName = '__artKey';
const setCSS = target.style.setProperty.bind(target.style);
async function onMouseOver({target: trg}) {
const key = trg.hasOwnProperty(artKeyPropName)
? trg[artKeyPropName]
: getArtKey(trg);
if (!key) return isVisible && this.toggle(false);
const self = this;
let isDisplayNeeded = true;
trg.addEventListener('mouseleave', function leave(e) {
this.removeEventListener(e.type, leave);
isDisplayNeeded = false;
isVisible && self.toggle(false);
});
const html = cache[key] || await setArtHTML(key).catch(setNoAccess);
if (!(isDisplayNeeded && html)) return;
target.innerHTML = html;
this.setPos(...this.getPos(trg));
this.toggle(true);
}
function getArtKey(el) {
if (el.tagName !== 'A') return setArtKey(el);
if (el.pathname !== '/art_info.php') return setArtKey(el);
return setArtKey(el, el.search.match(/id=([^&]+)/)[1]);
}
function setArtKey(el, key = null) {
return el[artKeyPropName] = key;
}
async function setArtHTML(id) {
const doc = await fetch.get(`/art_info.php?id=${id}`);
return (cache[id] = $('#set_mobile_max_width', doc).innerHTML);
}
function getArtPos(el) {
const {top, bottom, right} = el.getBoundingClientRect();
const h = target.offsetHeight;
const y = bottom + h + 2 > view.innerHeight ? Math.abs(top - h) : bottom;
return [~~right, ~~y];
}
return {
__init__() {
onMouseOver = onMouseOver.bind(this);
aucElem.addEventListener('mouseover', debounce(onMouseOver, 350));
target.addEventListener('mouseover', (e) => e.stopPropagation());
},
getPos(elem) {
return getArtPos(elem);
},
setPos(x, y) {
setCSS('--x', `${x}px`);
setCSS('--y', `${y}px`);
},
toggle(force) {
isVisible = force;
target.classList.toggle('__shown', isVisible);
}
};
})($('#art-info'));
const form = ((target) => {
const lotElem = $('#form__lot');
const input = $('#form__input');
const submitBtn = $('#form__submit');
let lotSaleLabel = '';
const calcSaleLabel = (id) => new Function('id', `return ${lotSaleLabel}`)(id);
const keyframesData = {
outlineColor: ['transparent', 'currentColor']
};
let inputAnimation = {
play: Function.prototype,
effect: { setKeyframes: Function.prototype }
};
if (view.Animation && view.KeyframeEffect) {
inputAnimation = new Animation(new KeyframeEffect(
input,
keyframesData,
{ duration: 250, direction: 'alternate', easing: 'ease', iterations: 4 }
));
}
const getMin = (lot, calc) => {
const val = !lot.betAmount ? lot.cost : calc(lot.myBet || lot.cost);
return lot.cat === 'res' ? Math.min(val, getResMax(lot)) : val;
};
const getMax = (lot) => {
const val = lot.cat === 'res' ? getResMax(lot) : lot.blitz || Infinity;
return Math.min(val, player.gold);
};
const getResMax = (lot) => {
const val = lot.key < 3 ? 180 : 360;
return val + val * 0.20;
};
async function submitLot(lot) {
const hwm_form = aucHwmForm.target;
attempt($('a[onclick]', hwm_form), el => {
lot.once ? el.click() : evalScript(el.nextElementSibling);
el.remove();
});
const hwm_input = $('input[type="text"]', hwm_form);
hwm_input.value = ~~input.value;
if (lot.once) {
const hwm_btn = $('input[type="submit"]', hwm_form);
hwm_btn.dispatchEvent(new MouseEvent('mousedown'));
const rnd = 54 + Math.random() * 54 >> 0;
await new Promise(resolve => setTimeout(resolve, rnd));
hwm_btn.dispatchEvent(new MouseEvent('mouseup'));
$(`#buy_num${lot.id}`, hwm_form).value = calcSaleLabel(+lot.id);
}
const res = await send(hwm_form);
return res && result.call(this, lot, res);
}
function evalScript({text}) {
new Function(text.match(/\{([^}]+)/)[1])();
}
async function send(hwm_form) {
const entry = [hwm_form.action, new FormData(hwm_form)];
const doc = await fetch.post(...entry).catch(() => ({ URL: '' }));
if (!doc.URL.includes('auction')) return setNoAccess();
const elem = $('.wbwhite center', doc);
const text = elem.textContent;
const textParts = ['null', 'Куплен', 'Вы лидер', 'ные данные', 'слишком мала', 'Минимальная ставка', 'закончены', 'Вы не можете', ' не меньше!', 'Некорректн'];
const textTypes = ['usual', 'success', 'success', 'error', 'error', 'error', 'error', 'error', 'error', 'error'];
const ind = textParts.findIndex(part => text.includes(part));
const type = textTypes[~ind && ind];
return {type, text};
}
function result(lot, {type, text}) {
const isWrongData = lot.once && text.includes('ные данные');
if (isWrongData) {
if (!wrongDataState) return repeatRequest.call(this, lot);
return Alert.error(`${text}\nТребуется перезагрузка страницы!`, {
isFinite: false,
onDestroy: () => location.reload()
});
}
Alert.print(type, text);
wrongDataState = false;
this.disable(false);
aucClassList.remove('__unallowed');
keyframesData.outlineColor[1] = type === 'error' ? '#f44336' : '#4caf50';
inputAnimation.effect.setKeyframes(keyframesData);
inputAnimation.play();
if (!lot.once && !/Минимальная ставка|закончены/.test(text)) {
lot.increaseBetAmount();
}
if (type === 'success') return ok.call(this, lot);
const newCost = text.includes('Минимальная ставка')
? +text.match(/\d+$/)[0]
: /слишком мала| не меньше!/.test(text)
? this.getMinBet(+input.value)
: 0;
if (newCost) return this.updateCost(lot, newCost);
input.focus();
}
let wrongDataState = false;
async function repeatRequest(lot) {
wrongDataState = true;
aucHwmForm.target.name = '@';
Alert.warn('Trying second request...');
this.submit(lot);
}
function ok(lot) {
if (lot.cat === 'res') resources.refresh(lot.resName, +input.value);
lot.refresh();
this.refreshByLot(lot);
if (lot.once) return;
bets.add(lot);
updateCostFromProtocol.call(this, lot);
}
async function updateCostFromProtocol(lot) {
const url = `/auction_lot_protocol.php?id=${lot.id}&crc=${lot.crc}`;
const doc = await fetch.get(url).catch(() => ({ URL: '' }));
if (!doc.URL.includes('auction')) return setNoAccess();
const elem = $('a.pi + b', doc);
return elem && this.updateCost(lot, ~~elem.textContent);
}
return {
__init__() {
input.addEventListener('input', onInput);
function onInput(e) {
const {value, max} = input;
const min = e.type === 'wheel' ? +input.min : 0;
input.value = Math.max(min, Math.min(~~value, +max));
}
input.addEventListener('keydown', (e) => {
if (e.key === 'Escape') return activeLot.target.click();
if (e.key === 'Enter') {
e.stopPropagation();
return submitBtn.click();
}
});
input.addEventListener('wheel', (e) => {
const factor = e.shiftKey ? 10 : e.ctrlKey ? 100 : e.altKey ? 1e3 : 1;
const step = (e.deltaY > 0 ? -1 : 1) * factor;
e.preventDefault();
input.value = step + ~~input.value;
onInput(e);
});
submitBtn.addEventListener('click', (e) => {
e.stopPropagation();
if (!input.checkValidity()) {
return Alert.error('Некорректное значение ввода!');
}
this.disable(true);
this.submit(findLot('id', lotElem.dataset.id));
});
},
lotElem,
minimize(test) {
if (test && activeLot) {
activeLot.target.classList.remove('__active');
activeLot = null;
}
return target.classList.toggle('__minimized', test);
},
disable(test) {
submitBtn.disabled = test;
submitBtn.classList.toggle('__sending', test);
},
refreshByLot(lot, value = 0) {
if (this.minimize(!!lot.completed)) return;
const {once, target} = lot;
const label = input.previousSibling;
const btnText = once ? 'Купить лот' : 'Сделать ставку';
lotElem.style = target.style.cssText;
lotElem.innerHTML = target.innerHTML;
Object.assign(lotElem.dataset, target.dataset);
submitBtn.disabled = input.disabled = player.gold < lot.cost;
submitBtn.innerHTML = `<span>${btnText}</span>`;
label.data = input.placeholder = once ? 'Кол-во' : 'Ставка';
input.min = once ? 1 : getMin(lot, this.getMinBet);
input.max = once ? lot.amount : getMax(lot);
input.value = Math.min(input.max, Math.max(input.min, value));
if (!input.disabled) input.focus();
},
async submit(lot) {
if (aucHwmForm.name.endsWith(lot.id)) return submitLot.call(this, lot);
const hwm_form = await lot.getRemoteHwmForm();
if (hwm_form === 0) return;
if (hwm_form) {
if (lot.once) {
const elem = hwm_form.closest('table.wb').parentNode;
lotSaleLabel = elem.textContent.match(/\({4}[^;]+/)[0];
}
aucHwmForm.replace(importNode(hwm_form));
return submitLot.call(this, lot);
}
Alert.error('Лот уже продан или завершен по тайм-ауту');
this.disable(false);
lot.complete();
},
updateCost(lot, bet) {
lot.cost = bet;
$('._cost .gold', lot.target).textContent = formatNum(bet);
this.refreshByLot(lot);
},
getMinBet(bet) {
const step = Math.round(bet * 0.01);
return bet + Math.max(3, step);
},
get inputValue() {
return input.value;
}
};
})($('#form'));
const bets = ((target) => {
let visibilityState = 0;
const tempStack = [];
const stack = new Map;
const myBets = userData.bets;
async function init(keys) {
keys = keys.filter(id => !stack.has(id));
visibilityState = 1;
step1();
if (!keys.length) return stepIn();
setLoadState(1);
const expired = [];
while (keys.length) {
let promises = keys.splice(0, 5).map(pullBetsFromServer);
await Promise.all(promises).catch(() => {
keys.splice(0);
setNoAccess();
});
}
async function pullBetsFromServer(id) {
const [search, isExpired] = getBetValues(id);
if (isExpired) return expired.push(id);
const doc = await fetch.get(getAucURL(search));
if (!doc.URL.includes(AUC_PATH)) return setNoAccess();
const form = $(`form[name$="${id}"]`, doc);
if (!form) return expired.push(id);
const cat = (doc.URL.match(/cat=(\w+)/) || [0, 'my'])[1];
stack.set(id, createNewLot(form.closest('tr.wb'), cat));
}
expired.forEach(id => delete myBets[id]);
target.dataset.counter = Object.keys(myBets).length;
expired.length && userData.update();
setLoadState(0);
stepIn();
}
function getBetValues(id) {
const data = myBets[id];
const isArray = typeof data !== 'string';
return isArray ? [data[0], Date.now() >= data[1]] : [data, false];
}
function step1() {
timers.clear();
target.classList.add('__active');
filters.disable(true);
form.minimize(true);
tempStack.splice(0, Infinity, ...allLots.splice(0));
}
function step2(lots) {
allLots.push(...lots);
sort[userData.sort]();
lotsBox.appendAll(filterLots());
timers.switchTimers();
}
function stepIn() {
const nowTime = Date.now();
const lots = [];
[...stack.values()].forEach(lot => {
const i = tempStack.findIndex(({id}) => id === lot.id);
if (~i) {
lot = tempStack[i];
stack.set(lot.id, lot);
}
if (lot.completed || nowTime >= lot.time[1]) {
bets.remove(lot);
return ~i && tempStack.splice(i, 1);
}
lots.push(lot);
});
step2(lots);
}
function stepOut() {
const nowTime = Date.now();
const lots = tempStack.splice(0).filter(lot => {
return !(lot.completed || nowTime >= lot.time[1]);
});
step2(lots);
}
function close() {
this.hide();
activeLot && form.minimize(true);
const {cat} = searchParams;
const stuffCats = ['res', 'elements', 'part', 'dom', 'cert', 'obj_share'];
filters.partial(stuffCats.includes(cat));
filters.disable(['my', 'obj_share'].includes(cat));
allLots.splice(0);
stepOut();
}
return {
__init__() {
target.addEventListener('click', async function handler(e) {
e.stopPropagation();
const keys = Object.keys(myBets);
if (!keys.length) {
Alert.log('Зарегистрированных ставок не найдено');
return;
}
this.removeEventListener(e.type, handler);
await init(keys);
this.addEventListener(e.type, onHandleClick);
});
const onHandleClick = (e) => {
e.stopPropagation();
if (!(visibilityState ^= 1)) return close.call(this);
step1();
stepIn();
};
const keys = Object.keys(myBets);
const extracts = keys.filter(id => {
if (!getBetValues(id)[1]) return true;
delete myBets[id];
});
target.dataset.counter = extracts.length;
if (keys.length !== extracts.length) userData.update();
},
createIconTpl() {
const title = 'Отслеживается в ставках';
return `<span class="i-watch" title="${title}">👁</span>`;
},
has(id) {
return myBets.hasOwnProperty(id);
},
add(lot) {
if (this.has(lot.id)) return;
myBets[lot.id] = [lot.search, lot.time[1]];
stack.set(lot.id, lot);
userData.update();
target.dataset.counter++;
attempt($('.lot__bet-amount', lot.target), el => {
el.before(parseNode(this.createIconTpl()));
});
},
remove(lot) {
if (!this.has(lot.id)) return;
delete myBets[lot.id];
stack.delete(lot.id);
userData.update();
target.dataset.counter--;
const isConnected = !!lot.target.offsetWidth;
isConnected && attempt($('.i-watch', lot.target), el => el.remove());
if (!visibilityState) return;
lot.isActive && form.minimize(true);
isConnected && lot.target.remove();
},
hide() {
visibilityState = 0;
target.classList.remove('__active');
},
get shown() {
return !!visibilityState;
}
};
})($('#mybets-btn'));
const contextmenu = ((target) => {
let lotElem = null;
let activeLine = null;
const commands = [
['select', 'Купить лот', 'ЛКМ'],
['reload', 'Обновить лот', 'Shift + R'],
['reloadAll', 'Обновить все'],
['goto', 'Перейти на страницу лота'],
['addBet', '«Мои ставки»: добавить'],
['console', 'Показать в консоли'],
];
function cmd(action, text, key = '') {
if (!action) return '';
const attrs = [
'class="contextmenu__item"',
`data-action="${action}"`,
`data-key="${key}"`,
];
return `<div ${attrs.join(' ')}>${text}</div>`;
}
function onKeyDown(e) {
const {key} = e;
e.preventDefault();
e.stopPropagation();
if (e.altKey || key === 'Escape') return close();
if (key === 'Home') return setActiveLine(target.firstElementChild);
if (key === 'End') return setActiveLine(target.lastElementChild);
if (key === 'Enter' && activeLine) return activeLine.click();
const match = /^(Arrow|Page)(Up|Down)$/.exec(key);
if (match) return activeNextLine(match[2] === 'Down');
}
function onMouseMove(e) {
const trg = e.target;
if (trg === this) return;
e.stopPropagation();
if (trg !== activeLine) setActiveLine(trg);
}
function onMouseMove2(e) {
if (!activeLine) return;
activeLine.classList.remove('__active');
activeLine = null;
}
function onWheel(e) {
if (!e.target.closest(`#${target.id}`)) close();
}
function close() {
this.hide();
}
function activeNextLine(isDirNext) {
const props = isDirNext
? ['nextElementSibling', 'firstElementChild']
: ['previousElementSibling', 'lastElementChild'];
setActiveLine(activeLine && activeLine[props[0]] || target[props[1]]);
}
function setActiveLine(elem) {
activeLine && activeLine.classList.remove('__active');
elem.classList.add('__active');
activeLine = elem;
}
function getContent({id, once, cat, search}) {
const isBetExist = !once && bets.has(id);
const isBetsOpen = bets.shown;
commands[0][1] = once ? 'Купить лот' : 'Сделать ставку';
commands[2][0] = isBetsOpen ? 'reloadAll' : '';
commands[3][0] = (cat === 'my' || search === location.search) ? '' : 'goto';
commands[4][0] = once ? '' : !isBetExist ? 'addBet' : 'removeBet';
commands[4][1] = once ? '' : !isBetExist
? '«Мои ставки»: добавить'
: ['Удалить', '«Мои ставки»: удалить'][isBetsOpen ^ 1];
return commands.map(arr => cmd(...arr)).join('');
}
return {
__init__() {
close = close.bind(this);
target.addEventListener('keydown', onKeyDown);
target.addEventListener('mousemove', onMouseMove);
target.addEventListener('contextmenu', (e) => e.preventDefault());
lotsBox.target.addEventListener('contextmenu', (e) => {
e.stopPropagation();
if (e.target.tagName === 'A') return;
e.preventDefault();
lotElem = e.target.closest('.lot');
if (lotElem) this.show(e, findLot('target', lotElem));
});
target.addEventListener('click', (e) => {
e.stopPropagation();
const {action} = e.target.dataset;
if (!action) return;
const lot = lotElem && findLot('id', lotElem.dataset.id);
if (!lot) return;
this.hide();
switch (action) {
case 'select':
lot.select();
setSortsPad();
return;
case 'reload': return lot.reload();
case 'reloadAll': return allLots.forEach(lot => lot.reload());
case 'goto': return goTo(lot.search);
case 'console': return console.log(lot);
case 'addBet': return bets.add(lot);
case 'removeBet': return bets.remove(lot);
}
});
},
hide() {
activeLine = null;
target.innerHTML = '';
if (lotElem) {
lotElem.classList.remove('__hovered');
lotElem = null;
}
aucClassList.remove('contextmenu-is-shown');
target.removeEventListener('blur', close);
document.removeEventListener('wheel', onWheel);
document.removeEventListener('mousemove', onMouseMove2);
},
show({clientX: cx, clientY: cy}, lot) {
target.innerHTML = getContent(lot);
lotElem.classList.add('__hovered');
aucClassList.add('contextmenu-is-shown');
target.addEventListener('blur', close);
document.addEventListener('wheel', onWheel);
document.addEventListener('mousemove', onMouseMove2);
const w = target.offsetWidth;
const h = target.offsetHeight;
const x = Math.min(cx, view.innerWidth - w - 2);
const y = cy < view.innerHeight - h - 2 ? cy : cy - h;
target.style.setProperty('--x', `${~~x}px`);
target.style.setProperty('--y', `${~~y}px`);
target.focus();
},
get shown() {
return !!target.offsetWidth;
}
};
})($('#contextmenu'));
// ====================
const changelog = (() => {
const items = [
'Пофиксены ссылки на протоколы лотов',
'Ресурсы в шапке теперь кликабельны и подвязаны к соответствующим разделам рынка',
`Печатный поиск теперь работает также с английской раскладкой клавиатуры.
Алсо: при активном фокусе можно переключать режим поиска сочетанием
<kbd>Alt</kbd> + <kbd>S</kbd>`,
];
const create = (item) => `<p class="changelog-item">${item}</p>`;
return {
items,
toString() {
return /*html*/`
<div id="changelog" class="ui-scroll">
<div class="cl-build">Build ${MODULE_VERSION}</div>
${items.map(create).join('')}
</div>
`.trim();
}
};
})();
class Alert {
constructor(data = {}) {
const props = this.props = {...Alert.defaultProps, ...data};
const target = this.target = Alert.create(props);
this.destroy = this.destroy.bind(this);
this.onKeyDown = this.onKeyDown.bind(this);
target.addEventListener('keydown', this.onKeyDown);
this.closeButton.addEventListener('click', this.destroy);
if (props.isFinite) {
this.onAnimationEnd = this.onAnimationEnd.bind(this);
target.addEventListener('animationend', this.onAnimationEnd);
}
}
static __init__() {
this.stack = new Set;
this.container = $('#notices', aucElem);
this.startMessages = isOldVersion ? [] : [changelog];
this.defaultProps = {
type: 'usual',
message: '...',
isFinite: true,
onCreate: Function.prototype,
onDestroy: Function.prototype,
};
}
static addStartMessage(msg) {
this.startMessages.push(msg);
}
static showStartMessages() {
this.startMessages.forEach(msg => this.log(msg));
}
static create({type, message, isFinite}) {
const classes = ['user-alert', `__${type}`];
isFinite && classes.push('__finite');
return parseNode(/*html*/`
<div class="${classes.join(' ')}" tabindex="-1">
<button class="user-alert__close">×</button>
<div class="user-alert__body">${message}</div>
</div>
`);
}
static print(type, message, data = {}) {
console.log(message);
if (message === changelog) {
type = 'changelog';
data.isFinite = false;
}
new this({...data, type, message}).show();
}
static log() {
return this.print('usual', ...arguments);
}
static warn() {
return this.print('warn', ...arguments);
}
static error() {
return this.print('error', ...arguments);
}
static ok() {
return this.print('success', ...arguments);
}
static get lastItem() {
return [...this.stack].pop();
}
get closeButton() {
return this.target.firstElementChild;
}
show() {
if (!Alert.lastActiveElement) {
Alert.lastActiveElement = document.activeElement || document.body;
}
Alert.stack.add(this);
Alert.container.prepend(this.target);
this.target.focus();
this.props.onCreate(this);
}
destroy() {
if (!Alert.stack.delete(this)) return;
const {target} = this;
this.closeButton.removeEventListener('click', this.destroy);
target.removeEventListener('animationend', this.onAnimationEnd);
target.removeEventListener('keydown', this.onKeyDown);
target.remove();
if (Alert.stack.size) Alert.lastItem.target.focus();
else if (Alert.lastActiveElement) {
Alert.lastActiveElement.focus();
Alert.lastActiveElement = null;
}
this.props.onDestroy(this);
}
onKeyDown(e) {
if (e.key !== 'Escape') return;
this.destroy();
}
onAnimationEnd(e) {
if (e.animationName !== 'userAlertProcessing') return;
this.destroy();
}
toString() {
return this.props.message;
}
}
Alert.__init__();
// ====================
view.addEventListener('offline', function() {
isOnLine = false;
aucClassList.add('__unallowed', '__disconnected');
Alert.error('Потеряно соединение с интернетом', {
isFinite: false,
onCreate: (that) => {
this.addEventListener('online', onOnline.bind(that), { once: true });
}
});
function onOnline() {
isOnLine = true;
this.destroy();
setLoadState(0);
form.disable(false);
aucClassList.remove('__unallowed', '__disconnected');
Alert.ok('Соединение восстановлено');
}
});
document.addEventListener('keydown', (e) => {
const {code, ctrlKey} = e;
e.stopPropagation();
if (!ctrlKey && code === 'F5') {
e.preventDefault();
loadPage();
return;
}
if (code === 'Escape') return artInfo.toggle(false);
if (ctrlKey && code === 'Slash') return $('#search').focus();
if (e.shiftKey && code === 'KeyR') {
const lot = lotsBox.selectedLot || findLot('isActive', true);
if (lot) lot.reload();
}
});
aucElem.addEventListener('click', (e) => {
const link = e.ctrlKey ? null : e.target.closest('a');
if (!(link && link.pathname === AUC_PATH)) return;
e.preventDefault();
e.stopPropagation();
goTo(link.search);
});
// ====================
resources.__init__();
player.__init__();
artsSelect.__init__();
setArtsSelect.__init__();
categories.__init__();
search.__init__();
faves.__init__();
bets.__init__();
filters.__init__();
sort.__init__();
artInfo.__init__();
form.__init__();
lotsBox.__init__();
contextmenu.__init__();
// ====================
let popStateTimerId = 0;
view.onpopstate = (e) => {
clearTimeout(popStateTimerId);
if (location.pathname !== AUC_PATH) return;
e.stopImmediatePropagation();
popStateTimerId = setTimeout(loadPage, 350);
};
document.body.replaceChildren(aucHwmForm.target, aucElem);
Alert.showStartMessages();
loadPage();
modules.add(MODULE_NAME, MODULE_VERSION);
})(document.defaultView);