chatapp-h5/h5/ranking/ranking.js
2026-04-24 19:45:21 +08:00

789 lines
25 KiB
JavaScript

(function () {
"use strict";
var API_BASE_URL = "https://jvapi.haiyihy.com";
var ASSET_BASE = "/assets/yumi-ranking/Ranking/Overall/";
var BG_VERSION = "20260424c";
var DEFAULT_AVATAR = "/assets/da.png";
var COIN_ICON = "";
var LOADING_GIF = "/assets/loading-ranking.gif";
var BACK_ICON =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADxSURBVHgB7dvBDYJAFEXRHyuhBEuzA+3EWAmlUIJ2MDJCNATy5m1I1H9PwoZhww3Mgh8iAAAAAACllG48joGlOUxfPoZ6LvCOM5S1PrITcV4is1acuhY7O8SXmveX+gp14rJbZGQ8OdUlMiKOQByBOAJxBOIIxBGIIxBHII5AHIE4AnEE4gjEEYgjEKeBOMJ488d/irPHN+lHYz33JKIqywHflnNkZm7SRCJSA5EMRDIQyUAkA5EMRDIQyUAkA5EMRDIQyUAkA5EMRDIQyWBGOkVmRqR7ZNeKFJCRroHJRqS+8DvUWpkGk10AAAAAwO96AiOznp1YXpZWAAAAAElFTkSuQmCC";
var RANKING_TYPES = ["Wealth", "Charm", "Room"];
var PERIODS = [
{ key: "Daily", api: "DAY", label: "ranking_daily" },
{ key: "Weekly", api: "WEEK", label: "ranking_weekly" },
{ key: "Monthly", api: "MONTH", label: "ranking_monthly" }
];
var TYPE_LABELS = {
Wealth: "ranking_wealth",
Charm: "ranking_charm",
Room: "ranking_room"
};
var TYPE_TO_MY_RANK = {
Wealth: "GIFTS_SEND",
Charm: "GIFTS_RECEIVED",
Room: "ROOM_GIFTS"
};
var TYPE_ENDPOINTS = {
Wealth: "/activity/leaderboard/gifts-send",
Charm: "/activity/leaderboard/gifts-received",
Room: "/activity/leaderboard/room-gifts"
};
var TYPE_ASSETS = {
Wealth: {
bg: "bgWealth",
top1: "rankAvatarFrame1",
top2: "rankAvatarFrame2",
top3: "rankAvatarFrame3"
},
Charm: {
bg: "bgCharm",
top1: "rankAvatarFrame1",
top2: "rankAvatarFrame2",
top3: "rankAvatarFrame3"
},
Room: {
bg: "bgRoom",
top1: "rankAvatarFrame1",
top2: "rankAvatarFrame2",
top3: "rankAvatarFrame3"
}
};
var I18N = {
en: {
ranking_wealth: "Wealth",
ranking_charm: "Charm",
ranking_room: "Room",
ranking_daily: "Daily",
ranking_weekly: "Weekly",
ranking_monthly: "Monthly",
loading: "Loading"
}
};
var commonHeaders = {
authorization: "Bearer undefined",
"req-app-intel": "version=1.0.0;build=1;model=SM-G9550;sysVersion=9;channel=Google",
"req-client": "Android",
"req-imei": "8fa54d728ab449e04f9292329ed44bda",
"req-lang": "id-ID",
"req-sys-origin": "origin=ATYOU;originChild=ATYOU",
"req-version": "V2",
"req-zone": "Asia/Shanghai"
};
var state = {
rankingType: getInitialRankingType(),
period: "Daily",
dateType: "DAY",
myRankType: "GIFTS_SEND",
sourceRanking: {},
visibleRanking: [],
myRanking: {},
visibleCount: 10,
hasMore: true,
loading: true,
locale: getLocale(),
isApp: isAppEnvironment(),
requestId: 0
};
var stickyObserver = null;
var loadObserver = null;
var lastTypeClick = 0;
var lastPeriodClick = 0;
function asset(name) {
return ASSET_BASE + name + ".png";
}
function backgroundAsset(type) {
return asset(TYPE_ASSETS[type].bg) + "?v=" + BG_VERSION;
}
function t(key) {
var messages = I18N[state.locale] || I18N.en;
return messages[key] || I18N.en[key] || key;
}
function getLocale() {
var raw = getParam("lang") || navigator.language || "en";
raw = String(raw).toLowerCase();
if (raw.indexOf("ar") === 0) return "ar";
if (raw.indexOf("tr") === 0) return "tr";
if (raw.indexOf("bn") === 0) return "bn";
return "en";
}
function getInitialRankingType() {
var first = getParam("first") || "Wealth";
return RANKING_TYPES.indexOf(first) >= 0 ? first : "Wealth";
}
function getParam(name) {
var hashQuery = "";
if (window.location.hash && window.location.hash.indexOf("?") >= 0) {
hashQuery = window.location.hash.slice(window.location.hash.indexOf("?") + 1);
}
var hashValue = hashQuery ? new URLSearchParams(hashQuery).get(name) : null;
var searchValue = new URLSearchParams(window.location.search).get(name);
return hashValue || searchValue;
}
function setHeadersFromApp(info) {
var next = {};
if (info.authorization !== undefined) next.authorization = info.authorization;
if (info.reqLang) next["req-lang"] = info.reqLang;
if (info.appVersion || info.buildVersion || info.appChannel) {
var appIntel = [];
if (info.appVersion) appIntel.push("version=" + info.appVersion);
if (info.buildVersion) appIntel.push("build=" + info.buildVersion);
if (info.appChannel) appIntel.push("channel=" + info.appChannel);
if (appIntel.length) next["req-app-intel"] = appIntel.join(";");
}
if (info.reqImei) next["req-imei"] = info.reqImei;
if (info.sysOrigin) {
var origin = ["origin=" + info.sysOrigin];
if (info.sysOriginChild) origin.push("child=" + info.sysOriginChild);
next["req-sys-origin"] = origin.join(";");
}
commonHeaders = Object.assign({}, commonHeaders, next);
}
function isMobileDevice() {
return /Android|iPad|iPhone|iPod/.test(navigator.userAgent);
}
function isAppEnvironment() {
return !!(window.app || window.webkit || window.FlutterPageControl);
}
function defaultBrowserHeaders() {
var lang = navigator.language || "";
return {
authorization: "",
reqLang: lang.toLowerCase().indexOf("ar") === 0
? "ar"
: lang.toLowerCase().indexOf("tr") === 0
? "tr"
: lang.toLowerCase().indexOf("bn") === 0
? "bn"
: "en",
appVersion: "1.0.0",
buildVersion: "1",
appChannel: "Web",
reqImei: "H5-STATIC",
sysOrigin: "LIKEI",
sysOriginChild: "LIKEI"
};
}
function mockAppAccessOrigin() {
return JSON.stringify({
Authorization: "Bearer FLUTTER_MOCK_TOKEN",
"Req-Lang": "en",
"Req-App-Intel": "build=1.0;version=2.1;channel=flutter;Req-Imei=flutter-device",
"Req-Sys-Origin": "origin=ATYOU;originChild=ATYOU"
});
}
function parseKeyValueList(value) {
var result = {};
if (!value) return result;
String(value).split(";").forEach(function (part) {
if (!part || part.indexOf("=") < 0) return;
var index = part.indexOf("=");
result[part.slice(0, index)] = part.slice(index + 1);
});
return result;
}
function normalizeAccessOrigin(data) {
if (!data) return {};
var appIntel = parseKeyValueList(data["Req-App-Intel"] || "");
var sysOrigin = parseKeyValueList(data["Req-Sys-Origin"] || "");
return {
reqLang: data["Req-Lang"],
authorization: data.Authorization,
buildVersion: appIntel.build,
appVersion: appIntel.version,
appChannel: appIntel.channel,
reqImei: appIntel["Req-Imei"],
sysOrigin: sysOrigin.origin,
sysOriginChild: sysOrigin.child
};
}
function getAccessOriginFromApp() {
return new Promise(function (resolve) {
var resolved = false;
var finish = function (value) {
if (resolved) return;
resolved = true;
resolve(value);
};
window.renderData = finish;
window.getIosAccessOriginParam = finish;
var attempts = 0;
var check = function () {
attempts += 1;
if (window.app && typeof window.app.getAccessOrigin === "function") {
try {
finish(window.app.getAccessOrigin());
} catch (error) {
console.error("getAccessOrigin failed:", error);
finish(mockAppAccessOrigin());
}
return;
}
if (attempts < 50) {
window.setTimeout(check, 100);
return;
}
if (window.FlutterApp && window.FlutterApp.postMessage) {
window.FlutterApp.postMessage("requestAccessOrigin");
}
finish(mockAppAccessOrigin());
};
if (isMobileDevice()) {
check();
} else {
finish(mockAppAccessOrigin());
}
});
}
async function initializeAppConnection() {
if (!isAppEnvironment()) {
setHeadersFromApp(defaultBrowserHeaders());
await fetchUserProfileAfterConnection();
return;
}
try {
var raw = await getAccessOriginFromApp();
var parsed = JSON.parse(raw);
setHeadersFromApp(normalizeAccessOrigin(parsed));
} catch (error) {
console.error("Failed to parse access origin:", error);
setHeadersFromApp(defaultBrowserHeaders());
}
await fetchUserProfileAfterConnection();
}
async function fetchUserProfileAfterConnection() {
try {
var response = await apiGet("/team/member/profile");
if (response && response.status && response.body) {
localStorage.setItem("userProfile", JSON.stringify(response.body));
}
} catch (error) {
console.warn("Failed to fetch user info after connection:", error);
}
}
async function apiRequest(path, options) {
var url = path.indexOf("http") === 0 ? path : API_BASE_URL + path;
var init = Object.assign({ method: "GET" }, options || {});
init.headers = Object.assign({}, commonHeaders, init.headers || {});
if (init.body && typeof init.body !== "string" && !(init.body instanceof FormData)) {
init.headers["Content-Type"] = "application/json";
init.body = JSON.stringify(init.body);
}
var response = await fetch(url, init);
var data = await response.json();
if (!response.ok) {
throw makeApiError("HTTP Error: " + response.status + " " + response.statusText, response.status, data);
}
if (data && data.status === false) {
throw makeApiError(data.errorMsg || data.message || "API Error: " + data.errorCode, response.status, data);
}
return data;
}
function apiGet(path) {
return apiRequest(path, { method: "GET" });
}
function makeApiError(message, status, response) {
var error = new Error(message);
error.name = "ApiError";
error.status = status || null;
error.response = response || null;
error.errorMsg = response && response.errorMsg;
error.errorCode = response && response.errorCode;
return error;
}
async function fetchLeaderboard(type) {
var response = await apiGet(TYPE_ENDPOINTS[type]);
if (response && response.status && response.body) {
state.sourceRanking = response.body;
updatePeriodRanking();
}
}
async function fetchMyRanking() {
var path = "/activity/leaderboard/my-rank?type=" +
encodeURIComponent(state.myRankType) +
"&dateType=" +
encodeURIComponent(state.dateType);
var response = await apiGet(path);
state.myRanking = response && response.status && response.body ? response.body : {};
}
function updatePeriodRanking() {
var body = state.sourceRanking || {};
var rows = [];
if (state.period === "Hourly" && body.hourly) rows = body.hourly;
if (state.period === "Daily" && body.daily) rows = body.daily;
if (state.period === "Weekly" && body.weekly) rows = body.weekly;
if (state.period === "Monthly" && body.monthly) rows = body.monthly;
state.visibleRanking = Array.isArray(rows) ? rows : [];
state.visibleCount = 10;
state.hasMore = true;
}
async function preloadImages(urls) {
await Promise.all(urls.map(function (url) {
return new Promise(function (resolve) {
var image = new Image();
image.onload = resolve;
image.onerror = resolve;
image.src = url;
});
}));
}
function preloadRankingAssets() {
return preloadImages([
backgroundAsset("Wealth"),
backgroundAsset("Charm"),
backgroundAsset("Room"),
asset("rankAvatarFrame1"),
asset("rankAvatarFrame2"),
asset("rankAvatarFrame3")
]);
}
async function loadInitialData() {
applyTypeState(state.rankingType);
render();
try {
await initializeAppConnection();
await Promise.all([
fetchCurrentRankingGroup(),
preloadRankingAssets()
]);
} catch (error) {
console.error("Ranking preload failed:", error);
} finally {
state.loading = false;
render();
}
}
async function fetchCurrentRankingGroup() {
var requestId = ++state.requestId;
var type = state.rankingType;
await Promise.all([
fetchLeaderboard(type).catch(function (error) {
console.error("Leaderboard request failed:", error);
}),
fetchMyRanking().catch(function (error) {
console.error("My ranking request failed:", error);
})
]);
if (requestId !== state.requestId) return;
render();
}
async function fetchOnlyMyRanking() {
var requestId = ++state.requestId;
try {
await fetchMyRanking();
} catch (error) {
console.error("My ranking request failed:", error);
}
if (requestId !== state.requestId) return;
render();
}
function applyTypeState(type) {
state.rankingType = type;
state.myRankType = TYPE_TO_MY_RANK[type];
}
function switchRankingType(type) {
if (state.rankingType === type) return;
var now = Date.now();
if (now - lastTypeClick < 1000) return;
lastTypeClick = now;
applyTypeState(type);
state.period = "Daily";
state.dateType = "DAY";
state.sourceRanking = {};
state.visibleRanking = [];
state.myRanking = {};
state.visibleCount = 10;
state.hasMore = true;
render();
fetchCurrentRankingGroup();
}
function switchPeriod(period) {
if (state.period === period.key) return;
var now = Date.now();
if (now - lastPeriodClick < 500) return;
lastPeriodClick = now;
state.period = period.key;
state.dateType = period.api;
state.visibleRanking = [];
state.myRanking = {};
updatePeriodRanking();
render();
fetchOnlyMyRanking();
}
function loadMoreRows() {
if (!state.hasMore) return;
var total = state.visibleRanking.filter(function (_, index) {
return index >= 3;
}).length;
var current = state.visibleCount;
if (current < total) {
state.visibleCount = Math.min(current + 10, total);
if (state.visibleCount >= total) state.hasMore = false;
render();
} else {
state.hasMore = false;
}
}
function getTopUsers() {
var list = state.visibleRanking.slice();
while (list.length < 3) {
list.push({
avatar: "",
id: "",
nickname: "",
quantityFormat: ""
});
}
return list.slice(0, 3);
}
function getListRows() {
return state.visibleRanking.filter(function (_, index) {
return index >= 3;
}).slice(0, state.visibleCount);
}
function topLayout(isTopOne) {
return {
width: isTopOne ? "44%" : "34%",
minHeight: isTopOne ? "66vw" : "55vw",
avatarLayer: "height:55%",
avatarWidth: isTopOne ? "45%" : "47%",
nameBox: isTopOne ? "height:6vw;width:55%" : "height:4.5vw;width:65%",
pillWidth: isTopOne ? "55%" : "70%",
infoStyle: isTopOne ? "bottom:27%" : "bottom:29%"
};
}
function render() {
var app = document.getElementById("app");
if (!app) return;
if (state.loading) {
app.innerHTML = renderLoading();
return;
}
app.innerHTML = renderRanking();
bindEvents();
setupObservers();
}
function renderBgLayer(zIndex) {
var style = zIndex === undefined ? "" : ' style="z-index:' + zIndex + '"';
return '<div class="bg-layer"' + style + '><img class="bg-image" src="' +
escapeAttribute(backgroundAsset(state.rankingType)) +
'" alt="background-0"></div>';
}
function renderLoading() {
return '<main class="ranking-page" data-ranking="' + state.rankingType + '">' +
'<div class="loading-container" style="color:#fff">' +
renderBgLayer() +
'<img src="' + LOADING_GIF + '" alt="" class="ranking-loading-image">' +
'<p>' + escapeHtml(t("loading")) + '...</p>' +
'</div>' +
'</main>';
}
function renderRanking() {
return '<main class="ranking-page" data-ranking="' + state.rankingType + '">' +
'<div class="ranking-content">' +
renderBgLayer(-1) +
'<div class="sentinel"></div>' +
renderHeader() +
'<div class="ranking-main">' +
renderTopSection() +
renderRankList() +
'</div>' +
'</div>' +
'<div class="bottom-spacer"></div>' +
renderMyRanking() +
'<div class="sr-status" aria-live="polite"></div>' +
'</main>';
}
function renderHeader() {
return '<div class="sticky-header">' +
'<div class="sticky-spacer"></div>' +
'<div class="type-tabs-wrap"><div class="type-tabs">' +
RANKING_TYPES.map(function (type) {
return '<button class="type-tab' + (state.rankingType === type ? " active" : "") +
'" data-ranking-type="' + type + '">' +
escapeHtml(t(TYPE_LABELS[type])) +
'</button>';
}).join("") +
'<button class="back-btn" type="button" aria-label="back"><img src="' + BACK_ICON + '" alt=""></button>' +
'</div></div>' +
'<div class="period-tabs">' +
PERIODS.map(function (period) {
return '<div class="period-item' + (state.period === period.key ? " active" : "") + '">' +
'<button class="period-tab" data-period="' + period.key + '">' +
escapeHtml(t(period.label)) +
'</button>' +
'</div>';
}).join("") +
'</div>' +
'</div>';
}
function renderTopSection() {
var users = getTopUsers();
return '<div class="top-section">' +
'<div class="top-one-wrap">' +
renderTopUser(users[0], 0, true) +
'</div>' +
'<div class="top-pair-wrap">' +
renderTopUser(users[1], 1, false) +
renderTopUser(users[2], 2, false) +
'</div>' +
'</div>';
}
function renderTopUser(user, index, isTopOne) {
var assets = TYPE_ASSETS[state.rankingType];
var frame = isTopOne ? assets.top1 : index === 1 ? assets.top2 : assets.top3;
var layout = topLayout(isTopOne);
var name = user && user.nickname ? user.nickname : "";
var avatar = user && user.avatar ? user.avatar : "";
var quantity = user && user.quantityFormat ? user.quantityFormat : "";
var id = user && user.id ? user.id : "";
return '<div class="top-user rank-' + (index + 1) + '" style="width:' + layout.width + '" data-user-id="' + escapeAttribute(id) + '">' +
'<div class="top-user-inner" style="min-height:' + layout.minHeight + '">' +
'<img class="top-frame" src="' + asset(frame) + '" alt="">' +
'<div class="top-avatar-layer" style="' + layout.avatarLayer + '">' +
'<div class="top-avatar-box" style="width:' + layout.avatarWidth + '">' +
'<img src="' + escapeAttribute(avatar) + '" alt="" data-avatar>' +
'</div>' +
'</div>' +
'<div class="top-user-info" style="' + layout.infoStyle + '">' +
'<div class="top-name-box" style="' + layout.nameBox + '">' +
'<div class="show-text ' + (isTopOne ? "top1-text" : "top-text") + '" style="font-weight:860">' + escapeHtml(name) + '</div>' +
'</div>' +
(quantity ? renderQuantityPill(quantity, layout.pillWidth, isTopOne) : "") +
'</div>' +
'</div>' +
'</div>';
}
function renderQuantityPill(quantity, width, isTopOne) {
return '<div class="quantity-pill" style="width:' + width + '">' +
'<div class="quantity-inner">' +
'<div class="quantity-text show-text ' + (isTopOne ? "top1-text" : "top-text") + '">' +
escapeHtml(quantity) +
'</div>' +
'</div>' +
'</div>';
}
function renderRankList() {
var rows = getListRows();
return '<div class="rank-list">' +
rows.map(function (row, index) {
return renderRankRow(row, index + 4);
}).join("") +
(state.hasMore ? '<div class="load-more-sentinel"></div>' : "") +
'</div>';
}
function renderItemCenter(classes, minHeight, image, content, attrs) {
return '<div class="item-center ' + classes + '"' + (attrs || "") + ' style="min-height:' + minHeight + '">' +
'<div class="item-content">' + content + '</div>' +
'</div>';
}
function renderRankRow(row, rank) {
var id = row && row.id ? row.id : "";
var avatar = row && row.avatar ? row.avatar : "";
var name = row && row.nickname ? row.nickname : "";
var quantity = row && row.quantityFormat ? row.quantityFormat : "";
var content = '<div class="rank-left">' +
'<div class="rank-number"><div>' + rank + '</div></div>' +
'<img class="avatar" src="' + escapeAttribute(avatar) + '" alt="" data-avatar>' +
'<div class="rank-name">' + escapeHtml(name) + '</div>' +
'</div>' +
'<div class="rank-value">' +
'<div class="rank-value-text">' + escapeHtml(quantity) + '</div>' +
'</div>';
return renderItemCenter(
"rank-row",
"19vw",
asset("RankingItem"),
content,
' data-user-id="' + escapeAttribute(id) + '"'
);
}
function renderMyRanking() {
var mine = state.myRanking || {};
var rank = mine.rank || 999;
var avatar = mine.avatar || "";
var name = mine.nickname || "";
var quantity = mine.quantityFormat || 0;
var content = '<div class="mine-left">' +
'<div class="mine-rank"><div>' + escapeHtml(String(rank)) + '</div></div>' +
'<img class="avatar" src="' + escapeAttribute(avatar) + '" alt="" data-avatar>' +
'<div class="mine-name">' + escapeHtml(name) + '</div>' +
'</div>' +
'<div class="mine-value">' +
'<div class="mine-value-text">' + escapeHtml(String(quantity)) + '</div>' +
'</div>';
return renderItemCenter("my-ranking", "", asset("myRankingBg"), content);
}
function bindEvents() {
document.querySelectorAll("[data-ranking-type]").forEach(function (button) {
button.addEventListener("click", function () {
switchRankingType(button.getAttribute("data-ranking-type"));
});
});
document.querySelectorAll("[data-period]").forEach(function (button) {
button.addEventListener("click", function () {
var key = button.getAttribute("data-period");
var period = PERIODS.filter(function (item) {
return item.key === key;
})[0];
if (period) switchPeriod(period);
});
});
var back = document.querySelector(".back-btn");
if (back) back.addEventListener("click", closePage);
document.querySelectorAll("[data-user-id]").forEach(function (node) {
node.addEventListener("click", function () {
openAppTarget(node.getAttribute("data-user-id"));
});
});
document.querySelectorAll("[data-avatar]").forEach(function (img) {
img.addEventListener("error", function () {
if (img.getAttribute("src") !== DEFAULT_AVATAR) {
img.setAttribute("src", DEFAULT_AVATAR);
}
});
});
}
function setupObservers() {
if (stickyObserver) stickyObserver.disconnect();
if (loadObserver) loadObserver.disconnect();
var sentinel = document.querySelector(".sentinel");
var stickyHeader = document.querySelector(".sticky-header");
if (sentinel && stickyHeader && "IntersectionObserver" in window) {
stickyObserver = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
stickyHeader.classList.remove("stuck");
} else {
stickyHeader.classList.add("stuck");
}
});
});
stickyObserver.observe(sentinel);
}
var loadMore = document.querySelector(".load-more-sentinel");
if (loadMore && "IntersectionObserver" in window) {
loadObserver = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting && state.hasMore) loadMoreRows();
});
}, { rootMargin: "100px" });
loadObserver.observe(loadMore);
}
}
function closePage() {
try {
if (window.app && window.app.closePage) {
window.app.closePage();
} else if (window.FlutterPageControl && window.FlutterPageControl.postMessage) {
window.FlutterPageControl.postMessage("close_page");
} else {
window.history.back();
}
} catch (error) {
console.error("close page failed:", error);
window.history.back();
}
}
function openAppTarget(id) {
if (!id || !state.isApp) return;
try {
if (state.rankingType === "Room") {
if (window.app && window.app.gotoRoom) {
window.app.gotoRoom(id);
} else if (window.FlutterPageControl && window.FlutterPageControl.postMessage) {
window.FlutterPageControl.postMessage("go_to_room:" + id);
}
} else if (window.app && window.app.viewUserInfo) {
window.app.viewUserInfo(id);
} else if (window.FlutterPageControl && window.FlutterPageControl.postMessage) {
window.FlutterPageControl.postMessage("view_user_info:" + id);
}
} catch (error) {
console.error("open app target failed:", error);
}
}
function escapeHtml(value) {
return String(value == null ? "" : value)
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
}
function escapeAttribute(value) {
return escapeHtml(value);
}
loadInitialData();
})();