// ==UserScript==
// @name CatWar Mod
// @name:ru Варомод
// @namespace https://catwar.su/blog482084
// @version 2.4.2
// @description Полезные дополнения для catwar.su
// @author Fredo14
// @copyright 2019—2020, Хвойница (https://catwar.su/cat209467)
// @license MIT; https://opensource.org/licenses/MIT
// @match https://*.catwar.su/*
// @grant none
// ==/UserScript==
(function (window, document, $) {
'use strict';
if (typeof $ === 'undefined') return;
const VERSION = '2.4.2';
const CONF_BLOGS_TAGS_OPEN = 'blogs_tags_open';
const CONF_SNIFF_TAGS1_OPEN = 'sniff_tags1_open';
const CONF_SNIFF_TAGS2_OPEN = 'sniff_tags2_open';
const CONF_LS_LAST_SEARCH = 'ls_last_search';
const CONF_LS_ENABLE_SAVING = 'ls_enable_saving';
const CONF_BLOGS_ANSWER_BUTTON = 'blogs_answer_btn';
const CONF_BLOGS_CITE_BUTTON = 'blogs_cite_btn';
const CONF_BLOGS_CITE_BUTTON_HIDE = 'blogs_cite_btn_hide';
const CONF_BLOGS_COMMENTS_SMILES = 'blogs_comments_smiles';
const CONF_BLOGS_AVATARS = 'blogs_avatars';
const CONF_BLOGS_AVATARS_SIZE = 'blogs_avatars_size';
const CONF_BLOGS_AVATARS_BORDER = 'blogs_avatars_border';
const CONF_BLOGS_AVATARS_NO_CROP = 'blogs_avatars_no_crop';
const CONF_BLOGS_IMAGES_MAX_WIDTH = 'blogs_img_width';
const CONF_SNIFF_IMAGES_MAX_WIDTH = 'sniff_img_width';
const CONF_INDEX_SAVE_ALERT = 'index_save_alert';
const CONF_CREATION_SAVE_ALERT = 'creation_save_alert';
const CONF_KNS_SAVE_ALERT = 'kns_save_alert';
const CONF_INDEX_EDUCATION_HIDE = 'index_education_hide';
const CONF_SETTINGS_HIDE_EMAIL = 'settings_hide_email';
const CONF_CAT_ADD_KRAFT_NUMBER = 'cat_add_kraft_number';
const CONF_CAT_ENABLE_NOTES = 'cat_enable_notes';
const CONF_FAE_SHOW_NOTES = 'fae_show_notes';
const CONF_CW3_ACT_END_IN_TITLE = 'cw3_act_end_in_title';
const CONF_CW3_ACT_END_ALERT = 'cw3_act_end_alert';
const CONF_CW3_ACT_END_ALERT_SOUND = 'cw3_act_end_alert_sound';
const CONF_CW3_ACT_END_ALERT_VOLUME = 'cw3_act_end_alert_volume';
const CONF_CW3_ACT_END_ALERT_TIME = 'cw3_act_end_alert_time';
const CONF_CW3_ACT_END_ALERT_BLUR_ONLY = 'cw3_act_end_blur_only';
const CONF_CW3_FIGHT_PANEL_HEIGHT = 'cw3_fight_panel_height';
const CONF_CW3_THEME = 'cw3_theme';
const CONF_CW3_COMPACT = 'cw3_compact';
const CONF_CW3_COMPACT_SWAP_SIDES = 'cw3_compact_swap_sides';
const CONF_CW3_COMPACT_CHAT_ON_TOP = 'cw3_compact_chat_on_top';
const CONF_CW3_COMPACT_ROUND_EDGES = 'cw3_compact_round_edges';
const CONF_CW3_COMPACT_SPLIT_INFO = 'cw3_compact_split_info';
const CONF_CW3_COMPACT_HIDE_HEADERS = 'cw3_compact_hide_headers';
const CONF_CW3_COMPACT_SPLIT_INFO_STICKY_HEADERS = 'cw3_compact_split_info_sticky_headers';
const CONF_CW3_BACKGROUND = 'cw3_bg';
const CONF_CW3_BACKGROUND_IMAGE = 'cw3_bg_image';
const CONF_CW3_BACKGROUND_SIZE = 'cw3_bg_size';
const CONF_CW3_BACKGROUND_POSITION = 'cw3_bg_position';
const CONF_CW3_WEATHER_SNOW = 'cw3_weather_snow';
const CONF_CW3_HIDE_SKY = 'cw3_hide_sky';
const CONF_CW3_CAGES_BORDERS = 'cw3_cages_borders';
const CONF_CW3_CHAT_LOUD_QUIETER = 'cw3_chat_loud_quieter';
const CONF_CW3_CHAT_QUIET_LOUDER = 'cw3_chat_quiet_louder';
const CONF_CW3_LOWER_CATS = 'cw3_lower_cats';
const CONF_CW3_LOWER_ARROWS = 'cw3_lower_arrows';
const CONF_CW3_DEAD_OPAQUE = 'cw3_dead_opaque';
const CONF_CW3_ADD_REALISM = 'cw3_add_realism';
const CONF_CW3_ALWAYS_DAY = 'cw3_always_day';
const CONF_CW3_MENU_TARGET_BLANK = 'cw3_menu_blank';
const CONF_CW3_MENU_ABOUT = 'cw3_menu_about';
const CONF_CW3_MENU_INDEX = 'cw3_menu_index';
const CONF_CW3_MENU_TOP = 'cw3_menu_top';
const CONF_CW3_MENU_CHAT = 'cw3_menu_chat';
const CONF_CW3_MENU_LS = 'cw3_menu_ls';
const CONF_CW3_MENU_LS0 = 'cw3_menu_ls0';
const CONF_CW3_MENU_BLOGS = 'cw3_menu_blogs';
const CONF_CW3_MENU_SNIFF = 'cw3_menu_sniff';
const CONF_CW3_MENU_SETTINGS = 'cw3_menu_settings';
const CONF_CW3_MENU_MOBILE = 'cw3_menu_mobile';
const CONF_CW3_HISTORY_NO_UNDERLINE = 'cw3_history_no_underline';
const CONF_CW3_CAT_INFO = 'cw3_cat_info';
const CONF_CW3_MODIFY_INVENTORY = 'cw3_modify_inventory';
const CONF_CW3_PARAMETERS_INFO = 'cw3_parameters_info';
const DEFAULTS = {};
DEFAULTS[CONF_BLOGS_TAGS_OPEN] = false;
DEFAULTS[CONF_SNIFF_TAGS1_OPEN] = false;
DEFAULTS[CONF_SNIFF_TAGS2_OPEN] = false;
DEFAULTS[CONF_LS_LAST_SEARCH] = { folder: 0, type: 1 };
DEFAULTS[CONF_LS_ENABLE_SAVING] = true;
DEFAULTS[CONF_INDEX_SAVE_ALERT] = false;
DEFAULTS[CONF_INDEX_EDUCATION_HIDE] = false;
DEFAULTS[CONF_CAT_ADD_KRAFT_NUMBER] = false;
DEFAULTS[CONF_CAT_ENABLE_NOTES] = true;
DEFAULTS[CONF_FAE_SHOW_NOTES] = true;
DEFAULTS[CONF_BLOGS_ANSWER_BUTTON] = true;
DEFAULTS[CONF_BLOGS_CITE_BUTTON] = true;
DEFAULTS[CONF_BLOGS_CITE_BUTTON_HIDE] = false;
DEFAULTS[CONF_BLOGS_COMMENTS_SMILES] = false;
DEFAULTS[CONF_BLOGS_AVATARS] = false;
DEFAULTS[CONF_BLOGS_AVATARS_SIZE] = 100;
DEFAULTS[CONF_BLOGS_AVATARS_BORDER] = true;
DEFAULTS[CONF_BLOGS_AVATARS_NO_CROP] = false;
DEFAULTS[CONF_BLOGS_IMAGES_MAX_WIDTH] = 0;
DEFAULTS[CONF_SNIFF_IMAGES_MAX_WIDTH] = 0;
DEFAULTS[CONF_CREATION_SAVE_ALERT] = false;
DEFAULTS[CONF_KNS_SAVE_ALERT] = false;
DEFAULTS[CONF_SETTINGS_HIDE_EMAIL] = false;
DEFAULTS[CONF_CW3_ACT_END_IN_TITLE] = false;
DEFAULTS[CONF_CW3_ACT_END_ALERT] = false;
DEFAULTS[CONF_CW3_ACT_END_ALERT_SOUND] = 'https://porch.website/cwmod/ding.mp3';
DEFAULTS[CONF_CW3_ACT_END_ALERT_VOLUME] = 1;
DEFAULTS[CONF_CW3_ACT_END_ALERT_TIME] = 1;
DEFAULTS[CONF_CW3_ACT_END_ALERT_BLUR_ONLY] = false;
DEFAULTS[CONF_CW3_FIGHT_PANEL_HEIGHT] = 70;
DEFAULTS[CONF_CW3_THEME] = 'default';
DEFAULTS[CONF_CW3_COMPACT] = false;
DEFAULTS[CONF_CW3_COMPACT_SWAP_SIDES] = false;
DEFAULTS[CONF_CW3_COMPACT_CHAT_ON_TOP] = true;
DEFAULTS[CONF_CW3_COMPACT_ROUND_EDGES] = false;
DEFAULTS[CONF_CW3_COMPACT_HIDE_HEADERS] = false;
DEFAULTS[CONF_CW3_COMPACT_SPLIT_INFO] = true;
DEFAULTS[CONF_CW3_COMPACT_SPLIT_INFO_STICKY_HEADERS] = true;
DEFAULTS[CONF_CW3_BACKGROUND] = 'default';
DEFAULTS[CONF_CW3_BACKGROUND_IMAGE] = '/cw3/sky/1.png';
DEFAULTS[CONF_CW3_BACKGROUND_SIZE] = 'auto';
DEFAULTS[CONF_CW3_BACKGROUND_POSITION] = 'top left';
DEFAULTS[CONF_CW3_WEATHER_SNOW] = false;
DEFAULTS[CONF_CW3_HIDE_SKY] = false;
DEFAULTS[CONF_CW3_CAGES_BORDERS] = false;
DEFAULTS[CONF_CW3_CHAT_LOUD_QUIETER] = false;
DEFAULTS[CONF_CW3_CHAT_QUIET_LOUDER] = false;
DEFAULTS[CONF_CW3_LOWER_CATS] = false;
DEFAULTS[CONF_CW3_LOWER_ARROWS] = true;
DEFAULTS[CONF_CW3_DEAD_OPAQUE] = false;
DEFAULTS[CONF_CW3_ADD_REALISM] = false;
DEFAULTS[CONF_CW3_ALWAYS_DAY] = false;
DEFAULTS[CONF_CW3_HISTORY_NO_UNDERLINE] = false;
DEFAULTS[CONF_CW3_CAT_INFO] = false;
DEFAULTS[CONF_CW3_MODIFY_INVENTORY] = false;
DEFAULTS[CONF_CW3_PARAMETERS_INFO] = true;
DEFAULTS[CONF_CW3_MENU_TARGET_BLANK] = false;
DEFAULTS[CONF_CW3_MENU_ABOUT] = false;
DEFAULTS[CONF_CW3_MENU_INDEX] = true;
DEFAULTS[CONF_CW3_MENU_TOP] = false;
DEFAULTS[CONF_CW3_MENU_CHAT] = true;
DEFAULTS[CONF_CW3_MENU_LS] = true;
DEFAULTS[CONF_CW3_MENU_LS0] = false;
DEFAULTS[CONF_CW3_MENU_BLOGS] = false;
DEFAULTS[CONF_CW3_MENU_SNIFF] = false;
DEFAULTS[CONF_CW3_MENU_SETTINGS] = true;
DEFAULTS[CONF_CW3_MENU_MOBILE] = false;
let SETTINGS = {};
let thisPageSettings = [];
const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'];
const catTimeStart = 1200000000000;
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
const isDesktop = isPage(/cw3\/(?!(kns|jagd))/) ? ($('#app').data('mobile') === 0) : ($('#branch').length);
const body = $('body');
if (!Date.prototype.toISOStringLocal) {
Date.prototype.toISOStringLocal = function () {
const d = new Date(+this);
let offset = d.getTimezoneOffset();
const sign = offset < 0 ? '+' : '-';
d.setUTCMinutes(d.getUTCMinutes() - d.getTimezoneOffset());
offset = ('0' + (offset / 60 | 0)).slice(-2) + ('0' + (offset % 60)).slice(-2);
return d.toISOString().replace(/Z\s*/i, '') + sign + offset;
};
}
try {
updateStorage();
loadSettings();
changeAllPages();
if (isPage(/cw3\/(?!(kns|jagd))/)) {
changeCW3Page();
}
else if (isPage('cw3/kns')) {
changeKnsPage();
}
else {
if ((isPage('', true) || isPage('index')) && $('#act_name b').length) {
changeIndexPage();
}
else if (isPage(/cat(\d+|\/.+)/)) changeCatPage();
else if (isPage('fae')) changeFaePage();
else if (isPage('chat')) changeChatPage();
else if (isPage('ls')) changeLsPage();
else if (isPage('ideas', true)) changeIdeasPage();
else if (isPage(/blog(?!sea)/) || isPage('sniff') || isPage('idea')) {
changeAllBlogsPages();
}
else if (isPage('settings', true)) changeSettingsPage();
}
} catch (err) {
window.console.error('Варомод:', err);
}
function updateStorage() {
// 2.0
Object.keys(window.localStorage).forEach(function (key) {
const savedNotes = JSON.parse(window.localStorage.getItem('cwmod_notes') || '{}');
if (/^cwm_settings/.test(key)) delete window.localStorage[key];
if (/^cwm_note/.test(key)) {
const catId = getNumber(key);
savedNotes[catId] = window.localStorage[key];
saveData('notes', savedNotes);
delete window.localStorage[key];
}
if (key === 'cwm_saved_chat') {
saveData('saved_chat', window.localStorage[key]);
delete window.localStorage[key];
}
});
}
function changeAllPages() {
const white = $('body > span').first();
if (white.length) {
white.children('a').css('color', '');
white.css('background-color', $('#site_table').css('background-color'));
}
const footer = $('#footer');
if (footer.length) {
const oldFooter = footer.html().split('<br>©');
footer.html(oldFooter[0] + ` | <a target="_blank" href="/settings#cwmod">Настройки</a><br>©` + oldFooter[1]);
}
let css = `
#cwmod-popup-wrap {
position: fixed;
left: 0;
top: 0;
z-index: 2;
width: 100%;
height: 100%;
display: none;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.5);
}
#cwmod-popup {
display: grid;
grid-gap: 1em;
max-height: 50vh;
width: 300px;
padding: 1em;
background: white;
color: black;
border: 1px solid black;
}
.cwmod-popup-btn:hover { text-decoration: none; }
.cwmod-popup-btn { display: none; text-align: center; color: #000033; text-decoration: underline; cursor: pointer; }
#cwmod-popup-reload { grid-area: reload; }
#cwmod-popup-cancel { grid-area: cancel; }
#cwmod-popup-hide { grid-area: hide; }
#cwmod-popup-text { grid-area: text; }
#cwmod-popup-text a { color: #123; }
#cwmod-popup-text a:hover { color: #246; }
.reload #cwmod-popup { grid-template-areas: 'text text' 'reload cancel'; }
.reload #cwmod-popup-reload, .reload #cwmod-popup-cancel { display: block; }
.alert #cwmod-popup { grid-template-areas: 'text' 'hide'; }
.alert #cwmod-popup-hide { display: block; }
.usn { user-select: none; }
.fs0 { font-size: 0; }
`;
addCSS(css);
body.append(`
<div class="reload" id="cwmod-popup-wrap">
<div id="cwmod-popup">
<div id="cwmod-popup-text"></div>
<div class="cwmod-popup-btn" id="cwmod-popup-reload" onclick="window.location.reload()">Обновить</div>
<div class="cwmod-popup-btn" id="cwmod-popup-cancel" onclick="$('#cwmod-popup-wrap').hide()">Позже</div>
<div class="cwmod-popup-btn" id="cwmod-popup-hide" onclick="$('#cwmod-popup-wrap').hide()">Скрыть</div>
</div>
</div>
`);
$(window).on('storage', function (e) {
if (e.originalEvent.key === 'cwmod_settings') {
const oldValue = JSON.parse(e.originalEvent.oldValue);
const newValue = JSON.parse(e.originalEvent.newValue);
Object.keys(newValue).forEach(function (key) {
if (thisPageSettings.indexOf(key) !== -1) {
if (oldValue[key] !== newValue[key]) {
let text = 'Настройки Варомода для этой страницы были изменены. Обновить страницу прямо сейчас, чтобы применить их?';
showCwmodPopup('reload', text);
}
}
});
}
});
body.on('click', 'summary.cwmod-settings', function () {
const th = $(this);
const key = th.data('conf');
setSettings(key, !th.parent().is('[open]'));
});
body.on('change', 'select.cwmod-settings', function () {
const th = $(this);
const key = th.data('conf');
let val = th.val();
if (/^\d+$/.test(val)) val = Number(val);
setSettings(key, val);
$(`[data-show="${key}"]`).each(function () {
let cond = $(this).data('cond');
const invert = /^!/.test(cond);
cond = cond.replace(/^!/, '');
if (invert !== (cond === val)) $(this).show();
else $(this).hide();
});
});
body.on('change', 'input.cwmod-settings', function () {
const th = $(this);
const key = th.data('conf');
const type = th.attr('type');
let val;
if (type === 'checkbox') {
val = th.is(':checked');
setSettings(key, val);
if (val) $(`[data-show="${key}"]`).show();
else $(`[data-show="${key}"]`).hide();
} else if (type === 'range') {
val = th.val();
setSettings(key, val);
}
});
body.on('input', 'input.cwmod-settings', function () {
const th = $(this);
const key = th.data('conf');
const type = th.attr('type');
if (type === 'number') {
if (th.val()) setSettings(key, Number(th.val()));
} else if (type === 'text') {
if (th.val()) setSettings(key, th.val());
}
});
body.on('click', '.cwmod-settings-set-default', function (e) {
e.preventDefault();
const th = $(this);
const key = th.data('rel');
const val = DEFAULTS[key];
const input = $(`[data-conf="${key}"]`);
if (input.attr('type') === 'text') input.val(val);
setSettings(key, val);
});
body.on('click', '.cwmod-settings-test-sound', function (e) {
e.preventDefault();
const th = $(this);
const audio = new Audio();
const volume = $(`[data-conf="${th.data('volume')}"]`).val();
audio.src = getSettings(th.data('audio'));
audio.volume = volume;
audio.pause();
audio.currentTime = 0;
audio.play();
});
if (getSettings(CONF_CAT_ENABLE_NOTES)) {
body.on('mouseenter', 'a:not(.headers)', function() {
const th = $(this);
const href = th.attr('href');
if (!/cat\d+/.test(href)) return;
const catId = /\d+/.exec(href)[0];
const note = getNoteByCatId(catId);
if (note) th.attr('title', note);
});
}
body.on('mouseenter', '.headers', function() {
$(this).attr('title', 'Это раскрывающийся блок');
});
}
function showCwmodPopup(type, text) {
$('#cwmod-popup-wrap').removeClass().addClass(type);
$('#cwmod-popup-text').html(text);
if ($('#cwmod-popup-wrap').css('display') === 'none') {
$('#cwmod-popup-wrap').css('display', 'flex');
}
}
function moonCalc() {
if (!$('#info').length) return;
addCSS(`.calc-error { color: darkred; }`);
$('#info').after('<div id="calc-age"></div>');
const infoObserver = new MutationObserver(function (mutations) {
mutations.forEach(function () {
const infoText = $('#info').text();
if (!infoText.match('Дата')) {
$('#calc-age').empty();
return;
}
const birthDateString = infoText.match(/\d{4}-\d\d-\d\d \d\d:\d\d/)[0].replace(' ', 'T');
const nowDateString = dateToString(new Date);
const moonsNow = getMoonsFromDate(birthDateString, nowDateString);
let bornWord;
const sex = $('[src^="//e.catwar.su/avatar"]').first()[0].style.borderColor;
const isRegDate = (/регистрац/.test(infoText) && $('#age2_icon').length);
switch (sex) {
case 'pink':
bornWord = isRegDate ? 'Зарегистрировалась' : 'Родилась';
break;
case 'blue':
bornWord = isRegDate ? 'Зарегистрировался' : 'Родилcя';
break;
default:
bornWord = isRegDate ? 'Зарегистрировалось' : 'Родилoсь';
}
const catTime = timestampToCatTime(Date.parse(birthDateString));
const catTimeString = `${catTime.day} ${months[catTime.month]} ${catTime.year} года в ${leadingZero(catTime.hour)}:${leadingZero(catTime.minute)}`;
$('#calc-age').html(`
<p><b>Калькулятор возраста</b></p>
<label>Дата и время: <input type="datetime-local" id="calc-date" min="${birthDateString}" value="${nowDateString}" max="9999-31-12T23:59"></label> <span id="calc-error-date" class="calc-error"></span>
<br><label>Возраст: <input type="number" id="calc-moons" min="0" step="0.1" value=${moonsNow} style="width: 60px"></label> <span id="moon-word">лун</span> <span id="calc-error-moons" class="calc-error"></span>
<br>${bornWord} ${catTimeString} по кошачьему времени.
<br><br>
`);
updateMoonWord(moonsNow);
$('#calc-date').on('input', function () {
$('#calc-error-date').empty();
const dateString = $('#calc-date').val();
const date = Date.parse(dateString);
if (isNaN(date)) {
if (dateString.length) $('#calc-error-date').html('Ошибка!');
return;
}
if (date < Date.parse(birthDateString)) {
$('#calc-error-date').html('Ошибка!');
return;
}
const moons = getMoonsFromDate(birthDateString, dateString);
$('#calc-moons').val(moons);
updateMoonWord(moons);
});
$('#calc-moons').on('input', function () {
$('#calc-error-moons').empty();
const moons = Number($('#calc-moons').val());
if (moons < 0 || isNaN(moons)) {
$('#calc-error-moons').html('Ошибка!');
return;
}
$('#calc-date').val(getDateStringFromMoons(birthDateString, moons));
updateMoonWord(moons);
});
});
});
infoObserver.observe(document.querySelector('#info'), { childList: true });
}
function updateMoonWord(moons) {
$('#moon-word').html(declOfNum(moons, ['луна', 'луны', 'лун']));
}
function getMoonsFromDate(birthDateString, dateString) {
const birthday = Date.parse(birthDateString);
const date = Date.parse(dateString);
const moons = Math.floor(convertTime('ms d', date - birthday) / 4 * 10) / 10;
return moons;
}
function getDateStringFromMoons(birthDateString, moons) {
const birthday = Date.parse(birthDateString);
const age = Math.round(convertTime('d ms', moons * 4));
return dateToString(birthday + age);
}
function changeAllBlogsPages() {
addBBcode(1);
let css = `
#blogs-reload > a, .poll-hasAnswered1 { color: black; }
.tags-list { margin: 0; }
.tags-list > li { list-style-type: circle; }
#add-tags p, #add-tags li { line-height: 1.4em; }
.add-tag {
padding: 1px 5px;
background-color: rgba(255, 255, 255, 0.8);
color: black;
border-radius: 1rem;
white-space: nowrap;
cursor: pointer;
}
.add-tag::before { content: '+ '; color: #888; }
#search > p { margin-top: 0.5em; }
.comment-answer, .comment-cite { display: inline-block; margin-top: 5px; }
`;
if (getSettings(CONF_BLOGS_CITE_BUTTON_HIDE)) {
css += `.comment-cite-wrap { display: none; }`;
}
if (isPage('blog')) {
if (getSettings(CONF_BLOGS_IMAGES_MAX_WIDTH)) {
css += `img {max-width: ${getSettings(CONF_BLOGS_IMAGES_MAX_WIDTH)}px}`;
}
}
if (isPage('sniff')) {
if (getSettings(CONF_SNIFF_IMAGES_MAX_WIDTH)) {
css += `img {max-width: ${getSettings(CONF_SNIFF_IMAGES_MAX_WIDTH)}px}`;
}
}
if (getSettings(CONF_BLOGS_AVATARS)) {
const width = getSettings(CONF_BLOGS_AVATARS_SIZE);
const border = getSettings(CONF_BLOGS_AVATARS_BORDER);
const size = getSettings(CONF_BLOGS_AVATARS_NO_CROP) ? 'contain' : 'cover';
css += `
.comment-avatar {
grid-area: avatar;
display: block;
width: ${width}px;
height: ${width}px;
${border ? 'border: 1px solid black;' : ''}
background-size: ${size};
background-repeat: no-repeat;
background-position: center;
}
.comment-info { grid-area: info; }
.comment-info + p { grid-area: p; }
.comment-text { grid-area: text; }
.comment-answer-buttons { grid-area: btns; }
.view-comment {
display: grid;
grid-template-areas: 'avatar info' 'avatar p' 'avatar text' 'btns btns';
grid-template-columns: ${width + 2 * border}px auto;/*я пожалею об этом*/
grid-column-gap: 10px;
}
`;
}
addCSS(css);
changeMainPage();
changeViewPage();
if (isPage('blogs?creation') || isPage('sniff?creation')) {
changeCreationPage();
}
const viewObserver = new MutationObserver(function (mutations) {
mutations.forEach(function () {
if ($('#view').css('display') === 'none') {
hideCommentPreview();
}
});
});
const creationObserver = new MutationObserver(function (mutations) {
mutations.forEach(function () {
if ($('#creation').css('display') === 'none') {
window.removeEventListener('beforeunload', beforeunload);
}
else {
changeCreationPage();
}
});
});
viewObserver.observe($('#view')[0], { attributes: true });
creationObserver.observe($('#creation')[0], { attributes: true });
}
function changeMainPage() {
$('#search > form > input[type="text"]').attr('placeholder', 'Поиск по ключевым словам');
$('#search').append(`<p><input id="search-tag" type="text" size="35" placeholder="Поиск по тегу"> <input id="search-ok" type="button" value="Искать"></p>`);
$('#search-ok').click(function () {
searchByTag($('#search-tag').val());
});
$('#search-tag').keypress(function (e) {
if (e.which == 13) {
searchByTag($('#search-tag').val());
return false;
}
});
}
function changeViewPage() {
const p = $('#send_comment_form > p:last-child');
p.prepend(`<input type="button" id="comment-preview" value="Предпросмотр"> `);
$('#send_comment_form').after(`
<p id="comment-preview-hide" style="display: none; margin: 0.5em 0;"><a href="#">Скрыть предпросмотр</a></p>
<div id="comment-preview-div" style="display :none"></div>
`);
const WS = io.connect(window.location.origin, {
path: '/ws/blogs/socket.io',
reconnectionDelay: 10000,
reconnectionDelayMax: 20000
});
WS.on('creation preview', function (data) {
$('#comment-preview-div').html(data).show();
$('#comment-preview-hide').show();
});
$('#comment-preview').click(function () {
WS.emit("creation preview", $('#comment').val());
});
$('#send_comment_form [type="submit"]').click(hideCommentPreview);
$('#comment-preview-hide').click(function (e) {
e.preventDefault();
hideCommentPreview();
});
if (getSettings(CONF_BLOGS_COMMENTS_SMILES)) {
p.append(`
<img src="smile/1.png" class="sticker" data-code=":sm1:">
<img src="smile/2.png" class="sticker" data-code=":sm2:">
<img src="smile/3.png" class="sticker" data-code=":sm3:">
<img src="smile/4.png" class="sticker" data-code=":sm4:">
<img src="smile/5.png" class="sticker" data-code=":sm5:">
<img src="smile/6.png" class="sticker" data-code=":sm6:">
<img src="smile/7.png" class="sticker" data-code=":sm7:">
<img src="smile/8.png" class="sticker" data-code=":sm8:">
<img src="smile/9.png" class="sticker" data-code=":sm9:">
<img src="smile/10.png" class="sticker" data-code=":sm10:">
`);
}
if ($('#comment').length) {
const commentObserver = new MutationObserver(function (mutations) {
mutations.forEach(changeComments);
});
commentObserver.observe(document.querySelector('#view_comments'), { childList: true });
}
let selectionInfo = {};
$('#view_comments').on('mouseup touchend', function () {
if (getSettings(CONF_BLOGS_CITE_BUTTON_HIDE)) $('.comment-cite-wrap').hide();
const sel = window.getSelection();
if (!sel.isCollapsed && sel.anchorNode && sel.focusNode) {
if (sel.anchorNode.parentElement.classList.contains('.comment-cite')) return;
else selectionInfo = {};
const anchor = {
elem: sel.anchorNode,
isComment: false,
id: 0
};
const focus = {
elem: sel.focusNode,
isComment: false,
id: 0
};
while (anchor.elem = anchor.elem.parentElement) {
if (anchor.elem.classList.contains('comment-text')) anchor.isComment = true;
if (anchor.elem.dataset.id) {
anchor.id = anchor.elem.dataset.id;
break;
}
}
while (focus.elem = focus.elem.parentElement) {
if (focus.elem.classList.contains('comment-text')) focus.isComment = true;
if (focus.elem.dataset.id) {
focus.id = focus.elem.dataset.id;
break;
}
}
if (anchor.isComment && focus.isComment && anchor.id === focus.id) {
selectionInfo.text = sel.toString();
selectionInfo.id = parseInt(anchor.id, 10);
$(`[data-id="${selectionInfo.id}"] .comment-cite-wrap`).show();
}
}
});
$('#view_comments').on('click', '.comment-answer', function (e) {
e.preventDefault();
answerComment($(this).parent().parent(), false);
});
$('#view_comments').on('click', '.comment-cite', function (e) {
e.preventDefault();
answerComment($(this).parent().parent().parent(), true, selectionInfo);
});
}
function hideCommentPreview() {
$('#comment-preview-hide').hide();
$('#comment-preview-div').empty().hide();
}
function changeComments() {
addAnswerButtons();
if (getSettings(CONF_BLOGS_AVATARS)) {
addCommentAvatars();
}
}
function addCommentAvatars() {
$('.view-comment:not(.has-avatar)').each(function () {
$(this).prepend('<div class="comment-avatar"></div>');
const commentId = $(this).data('id');
const avatarSelector = `.view-comment[data-id="${commentId}"] > .comment-avatar`;
const avatarDiv = $(avatarSelector);
const author = $(this).children('.comment-info').children('.author');
const catId = author.length ? getNumber(author.attr('href')) : 0;
const storedAvatar = window.sessionStorage.getItem('avatar' + catId);
if (catId === 0) {
avatarDiv.css('background-image', `url(//e.catwar.su/avatar/0.jpg)`);
} else if (storedAvatar) {
avatarDiv.css('background-image', `url(${storedAvatar})`);
} else {
setAvatar(catId, avatarSelector);
}
$(this).addClass('has-avatar');
});
}
function addAnswerButtons() {
const answerButton = isDesktop ? 'Ответить' : '🗨';
const citeButton = isDesktop ? 'Цитировать' : '💬';
const addAnswer = getSettings(CONF_BLOGS_ANSWER_BUTTON);
const addCite = getSettings(CONF_BLOGS_CITE_BUTTON);
$('.view-comment:not(.has-buttons)').each(function () {
let html = `<p class="comment-answer-buttons">`;
const notMyComment = $(this).children('.comment-info').children('[data-candelete="0"]').css('display') !== 'none';
if (addAnswer && notMyComment) {
html += `<a class="comment-answer" href="#">${answerButton}</a>`;
}
if (addCite) {
html += '<span class="comment-cite-wrap">';
if (addAnswer && notMyComment) html += ' | '
html += `<a class="comment-cite" href="#">${citeButton}</a></span>`;
}
$(this).append(html).addClass('has-buttons');
});
}
function answerComment(comment, cite, selectionInfo) {
const commentInfo = comment.children('.comment-info');
const num = commentInfo.children('b').children('.num').text();
let author;
if (commentInfo.children('.author').length) author = '[link' + getNumber(commentInfo.children('.author').attr('href')) + ']';
else author = '[b][code]' + commentInfo.children('span').first().text() + '[/code][/b]';
let quote;
if (cite) {
let text;
if (selectionInfo.id === comment.data('id')) text = selectionInfo.text;
else text = bbencode(comment.children('.comment-text').children('.parsed').html());
const date = findDate(commentInfo.html());
quote = `[table][tr][td][size=10][i]Цитата:[/i] [b]#${num}[/b] ${date} @ ${author}[/size][/td][/tr][tr][td][table=0][tr][td] [/td][td]${text}[/td][/tr][/table][/td][/tr][/table]`;
}
else {
quote = `${author} (#${num}), `;
}
const textarea = $('#comment');
textarea.val(textarea.val() + quote);
textarea.focus();
}
function changeCreationPage() {
if (getSettings(CONF_CREATION_SAVE_ALERT)) addSaveAlert();
if (isPage('blogs?creation', true) || isPage('sniff?creation', true)) {
const blogsTags = `
<details id="add-tags"${getSettings(CONF_BLOGS_TAGS_OPEN) ? ' open' : ''}>
<summary class="cwmod-settings" data-conf="${CONF_BLOGS_TAGS_OPEN}"><b>Добавить теги</b></summary>
<p>
<span class="add-tag">информация</span>
<span class="add-tag">новичкам</span>
<span class="add-tag">племенной блог</span>
</p>
<p>
<span class="add-tag">поздравление</span>
<span class="add-tag">день рождения</span>
<span class="add-tag">годовщина</span>
<span class="add-tag">самопоздравление</span>
</p>
<p>
<span class="add-tag">писательское творчество</span>
<span class="add-tag">стихотворения</span>
<span class="add-tag">рисунки</span>
<span class="add-tag">фотографии</span>
<span class="add-tag">рукоделие</span>
<span class="add-tag">журнал</span>
</p>
<p>
<span class="add-tag">неграмотно</span>
<span class="add-tag">мало</span>
<span class="add-tag">скопировано</span>
<span class="add-tag">опасно для глаз</span>
</p>
<p><span class="add-tag">сходка</span></p>
<p><span class="add-tag">конкурс</span></p>
</details>
`;
const sniffTags = `
<details id="add-tags"${getSettings(CONF_SNIFF_TAGS1_OPEN) ? ' open' : ''}>
<summary class="cwmod-settings" data-conf="${CONF_SNIFF_TAGS1_OPEN}"><b>Добавить теги</b></summary>
<p><small>Основано на блоге <a href="/blog331589">Ликбез</a>. Инструкция по выбору тегов там, а это кнопки для тех, кому лень писать их руками.</small></p>
<p><span class="add-tag">изображение</span></p>
<ul class="tags-list">
<li><span class="add-tag">скриншот</span> <span class="add-tag">достижение</span> <span class="add-tag">максимальное достижение</span> <span class="add-tag">звуки в Игровой</span> <span class="add-tag">скриншот Игровой</span> <span class="add-tag">скриншот кота</span> <span class="add-tag">скриншот профиля</span></li>
<li><span class="add-tag">фотография</span> <span class="add-tag">фотография автора</span> <span class="add-tag">фотография питомца</span> <span class="add-tag">фотография природы</span></li>
<li><span class="add-tag">действие</span> <span class="add-tag">дизайн</span> <span class="add-tag">запах</span> <span class="add-tag">локация</span> <span class="add-tag">медалька</span> <span class="add-tag">мем</span> <span class="add-tag">небо</span> <span class="add-tag">предмет</span> <span class="add-tag">рисунок</span></li>
</ul>
<p><span class="add-tag">Поднюхано</span> <span class="add-tag">Замышеголовили</span></p>
<ul class="tags-list">
<li><span class="add-tag">бугурт</span> <span class="add-tag">искусство</span> <span class="add-tag">Игровая</span> <span class="add-tag">критика</span> <span class="add-tag">милота</span> <span class="add-tag">обновление</span> <span class="add-tag">племенные новости</span> <span class="add-tag">творчество</span> <span class="add-tag">точка зрения</span></li>
</ul>
<p><span class="add-tag">Флудильня</span></p>
<ul class="tags-list">
<li><span class="add-tag">кроли</span> <span class="add-tag">локации за кроли</span> <span class="add-tag">о себе за кроли</span> <span class="add-tag">предметы за кроли</span> <span class="add-tag">рисунки за кроли</span> <span class="add-tag">услуги за кроли</span></li>
<li><span class="add-tag">пыль</span> <span class="add-tag">предметы за пыль</span> <span class="add-tag">рисунки за пыль</span> <span class="add-tag">услуги за пыль</span></li>
<li><span class="add-tag">рисунки за деньги</span></li>
<li><span class="add-tag">ролевая</span> <span class="add-tag">приглашение в ролевую</span></li>
<li><span class="add-tag">72</span> <span class="add-tag">адопт</span> <span class="add-tag">аукцион</span> <span class="add-tag">битва окрасов</span> <span class="add-tag">бугурт</span> <span class="add-tag">варомявы</span> <span class="add-tag">выбор племени</span> <span class="add-tag">гиф</span> <span class="add-tag">Голодные игры</span> <span class="add-tag">желание</span> <span class="add-tag">игра</span> <span class="add-tag">Игровая</span> <span class="add-tag">имя</span> <span class="add-tag">карта</span> <span class="add-tag">квест</span> <span class="add-tag">квест-опрос</span> <span class="add-tag">клон</span> <span class="add-tag">комикс</span> <span class="add-tag">лотерея</span> <span class="add-tag">обмен</span> <span class="add-tag">обмен предметов</span> <span class="add-tag">окрас</span> <span class="add-tag">покраска лайнов</span> <span class="add-tag">рабство</span> <span class="add-tag">симулятор</span> <span class="add-tag">сторонняя игра</span> <span class="add-tag">халява</span></li>
</ul>
<p>Общие теги:</p>
<ul class="tags-list">
<li><span class="add-tag">реальность</span> <span class="add-tag">учёба</span> <span class="add-tag">школа</span> <span class="add-tag">сон</span> <span class="add-tag">семья</span></li>
<li><span class="add-tag">поиск</span> <span class="add-tag">поиск друзей</span> <span class="add-tag">поиск кота</span> <span class="add-tag">поиск напарника</span> <span class="add-tag">поиск пары</span> <span class="add-tag">поиск семьи</span> <span class="add-tag">поиск художника</span></li>
<li><span class="add-tag">вопрос</span> <span class="add-tag">опрос</span> <span class="add-tag">помощь</span></li>
</ul>
<details${getSettings(CONF_SNIFF_TAGS2_OPEN) ? ' open' : ''}>
<summary class="cwmod-settings" data-conf="${CONF_SNIFF_TAGS2_OPEN}"><b>Теги вселенных и фракций</b></summary>
<p>Мёртвые:
<span class="add-tag">Звёздное племя</span>
<span class="add-tag">Сумрачный лес</span>
<span class="add-tag">Душевая</span>
</p>
<p>Озёрная вселенная:
<span class="add-tag">Грозовое племя</span>
<span class="add-tag">племя Ветра</span>
<span class="add-tag">Речное племя</span>
<span class="add-tag">племя Теней</span>
<span class="add-tag">клан Падающей Воды</span>
<span class="add-tag">Северный клан</span>
<span class="add-tag">Домашние</span>
<span class="add-tag">одиночки ОВ</span>
<span class="add-tag">Озёрная вселенная</span>
</p>
<p>Морская вселенная:
<span class="add-tag">Морское племя</span>
<span class="add-tag">племя Солнца</span>
<span class="add-tag">племя Луны</span>
<span class="add-tag">одиночки МВ</span>
<span class="add-tag">Морская вселенная</span>
</p>
<p>Вселенная творцов:
<span class="add-tag">племя Неразгаданных Тайн</span>
<span class="add-tag">Крылатое племя</span>
<span class="add-tag">Сплочённый Союз Свободных Республик</span>
<span class="add-tag">клан Ледяного Дождя</span>
<span class="add-tag">Эльфийские земли</span>
<span class="add-tag">Чернолесье</span>
<span class="add-tag">одиночки ВТ</span>
<span class="add-tag">Вселенная творцов</span>
</p>
</details>
</details>
`;
const tagsInput = $('#creation-tags');
if (!$('#add-tags').length) {
if (isPage('blogs')) tagsInput.parent().after(blogsTags);
else if (isPage('sniff')) tagsInput.parent().after(sniffTags);
$('.add-tag').click(function () {
let tags = tagsInput.val();
if (tags) tags += ', ';
tags += $(this).text();
tagsInput.val(tags);
tagsInput.focus();
});
}
//Сохранение последнего блога/поста
const creationInput = $('#creation-text');
if (creationInput.length) {
const key = isPage('blogs') ? 'cwm_saved_blog' : 'cwm_saved_sniff';
const oldText = window.localStorage.getItem(key);
if (oldText && !creationInput.val()) creationInput.val(oldText);
creationInput.on('input', function () {
window.localStorage.setItem(key, creationInput.val());
});
}
}
}
function searchByTag(tag) {
window.location.href = window.location.href.split('?')[0] + '?tag=' + tag;
}
function changeCatPage() {
addCSS(`#info { color: black; } #age_icon, #age2_icon, #act_icon, img[src^="medal"] { cursor: pointer; }`);
moonCalc();
if ($('[src="img/icon_kraft.png"]').length) {
if (getSettings(CONF_CAT_ADD_KRAFT_NUMBER)) {
const kraftArr = ['блоха', 'котёночек', 'задира', 'гроза детской', 'страх барсуков', 'победитель псов', 'защитник племени', 'великий воин', 'достоин Львиного племени', 'идеальная'];
const b = $('[src="img/icon_kraft.png"]').parent().siblings().children('b');
b.append(' (' + kraftArr.indexOf(b.text()) + ')');
}
}
if (getSettings(CONF_CAT_ENABLE_NOTES)) {
let p, catId;
if (isDesktop) {
p = $('#branch > p').first();
catId = p.data('cat');
$('#branch').prepend(`<textarea id="note" placeholder="Заметка об игроке. Её можете видеть только вы" style="float: right; min-width: 100px; width: 250px; max-width: 500px; height: 100px;"></textarea>`);
}
else {
p = $('#site_table > p').first();
catId = p.data('cat');
p.append(`<textarea id="note" placeholder="Заметка об игроке. Её можете видеть только вы" style="display: block; width: calc(100% - 10px); height: 50px;"></textarea>`);
}
const oldText = getNoteByCatId(catId);
const textarea = $('#note');
if (oldText && !textarea.val()) textarea.val(oldText);
const savedNotes = JSON.parse(window.localStorage.getItem('cwmod_notes') || '{}');
textarea.on('input', function () {
savedNotes[catId] = textarea.val();
if (!savedNotes[catId]) delete savedNotes[catId];
saveData('notes', savedNotes);
});
}
const medals = $('img[src^="medal"]');
if (medals.length) {
let lastpic = false;
medals.last().after(`<div id="infomedal" style="display: none; margin: 5px; padding: 5px; border-radius: 10px; width: 270px; background: rgba(255, 255, 255, 0.3); color: black;"></div>`);
const info = $('#infomedal');
$.getJSON('https://porch.website/get?file=medals&type=json', function (data) {
let medalsList = data.data;
medals.click(function () {
const picURL = $(this).attr('src');
const pic = getNumber(picURL);
if (pic === lastpic) {
info.hide(200);
lastpic = '';
} else {
if (info.css('display') === 'none') info.show(200);
lastpic = pic;
const medalInfo = medalsList[pic];
if (medalInfo) {
let status = medalInfo[1];
let transfer = medalInfo[2];
let getting = medalInfo[3];
let whose = medalInfo[4];
let about = `<br><b>${$(this).attr('alt')}</b>`;
if (!(status || transfer || getting || whose === 'Сайтовая')) about += '<br><i>Нет информации</i>';
else {
about += '<span style="font-size: 0.9em">';
if (status) {
let color;
if (status === 'выдаётся') color = 'green';
else if (status === 'не выдаётся') color = '#ba0000';
else color = 'gray';
about += `<br>Статус: <b style="color: ${color}">${status}</b>`;
}
if (transfer === 'возможен') about += `<br>Перенос на другого персонажа <b style="color: green">возможен</b>`;
else if (transfer === 'невозможен') about += `<br>Перенос на другого персонажа <b style="color: #ba0000">невозможен</b>`;
about += '</span>';
if (getting) about += `<br><span style="white-space:pre-wrap">${getting}</span>`;
if (whose === 'Сайтовая') about += `<br><span style="font-size: 0.9em">Это сайтовая медаль.</span>`;
}
info.html(`Медаль № ${pic}${about}`);
}
else {
info.html(`Медаль № ${pic}<br><b>${$(this).attr('alt')}</b><br><i>Нет информации</i>`);
}
}
});
});
}
}
function changeChatPage() {
addCSS(`.tabName, #confirm_text, .mess_tr[style^="background: rgb(255, 204, 153)"] { color: black; } .mess_tr[style^="background: rgb(255, 204, 153)"] a { color: #003; }`);
addBBcode(1);
const key = 'cwmod_saved_chat';
const oldText = window.localStorage.getItem(key);
if (oldText) $('#mess').html(oldText);
$('#mess').on('input', function () {
window.localStorage.setItem(key, $('#mess').html());
});
const observer = new MutationObserver(function (mutations) {
mutations.forEach(function () {
if (!$('#mess').html()) window.localStorage.removeItem(key);
});
});
observer.observe(document.querySelector('#mess'), { childList: true });
}
function changeCW3Page() {
const menu = $('.small').first();
//const isMale = /Мой кот/.test(menu.text());
const target = getSettings(CONF_CW3_MENU_TARGET_BLANK) ? 'target="_blank"' : '';
const menuButtons = {};
menuButtons[CONF_CW3_MENU_ABOUT] = `<a ${target} href="/about">Об игре</a>`;
//menuButtons[CONF_CW3_MENU_INDEX] = `<a ${target} href="/">${isMale ? 'Мой кот' : 'Моя кошка'}</a>`;
menuButtons[CONF_CW3_MENU_TOP] = `<a ${target} href="/top">СИ</a>`;
//menuButtons[CONF_CW3_MENU_CHAT] = `<a ${target} href="/chat">Чат</a><span id="newchat"></span>`;
//menuButtons[CONF_CW3_MENU_LS] = `<a ${target} href="/ls">ЛС</a><span id="newls"></span>`;
menuButtons[CONF_CW3_MENU_LS0] = `<a ${target} href="/ls?id=0">Памятка</a>`;
menuButtons[CONF_CW3_MENU_BLOGS] = `<a ${target} href="/blogs">Блоги</a>`;
menuButtons[CONF_CW3_MENU_SNIFF] = `<a ${target} href="/sniff">Лента</a>`;
menuButtons[CONF_CW3_MENU_SETTINGS] = `<a ${target} href="/settings#cwmod">Настройки</a>`;
menuButtons[CONF_CW3_MENU_MOBILE] = `<a href="/mobile">Сменить версию</a>`;
Object.keys(menuButtons).forEach(function (key) {
if (getSettings(key)) {
menu.append(' | ' + menuButtons[key]);
}
});
let css = '';
if (getSettings(CONF_CW3_CHAT_QUIET_LOUDER)) {
css += `.vlm0, .vlm1, .vlm2, .vlm3, .vlm4 {font-size: 12px;}`;
}
if (getSettings(CONF_CW3_CHAT_LOUD_QUIETER)) {
css += `.vlm6, .vlm7, .vlm8, .vlm9, .vlm10 {font-size: 14px;}`;
}
if (getSettings(CONF_CW3_LOWER_CATS)) {
css += `.d, .d div {background-position: left bottom;}`;
}
if (getSettings(CONF_CW3_FIGHT_PANEL_HEIGHT)) {
const height = getSettings(CONF_CW3_FIGHT_PANEL_HEIGHT);
if (height !== 70) {
css += `
#fightPanel { height: max-content; }
#fightLog { overflow-y: auto; min-height: 70px; height: unset !important; max-height: ${height}px; }
`;
}
}
if (getSettings(CONF_CW3_ADD_REALISM)) {
css += `.d {background-image: url(https://porch.website/cwmod/cat.png) !important;}`;
}
if (getSettings(CONF_CW3_CAGES_BORDERS)) {
css += `.cage {box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.33), inset -1px -1px 1px rgba(255, 255, 255, 0.33);}`;
}
if (getSettings(CONF_CW3_DEAD_OPAQUE)) {
css += `.cat > div {opacity: 1 !important;}`;
}
if (getSettings(CONF_CW3_HIDE_SKY)) {
css += `#tr_sky {display: none;}`;
}
if (getSettings(CONF_CW3_ALWAYS_DAY)) {
css += `#cages_div {opacity: 1 !important;}`;
}
if (getSettings(CONF_CW3_HISTORY_NO_UNDERLINE)) {
css += `#ist > a {text-decoration: none;}`;
}
if (getSettings(CONF_CW3_COMPACT)) {
css += `
#app { width: 100%; height: 1000px; }
#main_table { width: 100%; max-width: unset; height: 100%; border-collapse: collapse; background: none !important; }
#main_table > tbody { display: grid; grid-row-gap: 5px; grid-template-columns: 1fr auto 1fr; }
#app > span.small { grid-area: links; position: fixed; z-index: 1; left: 5px; top: 5px; }
#tr_chat { grid-area: chat; }
#tr_actions { grid-area: actions; overflow: auto; background: none !important; }
#tr_tos { grid-area: tos; background: none !important; }
#tr_sky { display: none; }
#tr_field { grid-area: field; background: black; }
#tr_mouth { grid-area: mouth; overflow: auto; background: none !important; }
#tr_actions > td, #tr_mouth > td, #info_main > tbody > tr > td { background-color: #ffdead; }
#tr_info { grid-area: info; max-height: 1000px; overflow-x: hidden; overflow-y: auto; }
#info_main { background: none !important; }
#info_main > tbody > tr > td, #tr_mouth > td > *, #tr_actions > td > *, #tr_chat { padding: 5px; }
#block_mess { margin: 0; padding: 8px 0; }
.infos { width: 100%; max-width: max-content; }
#itemList { width: 400px; max-height: 75px; overflow-y: auto; }
#thdey > br { display: none; }
#chat_form { display: grid; grid-row-gap: 5px; margin: 10px 5px 5px 5px; }
.chat_text { width: unset !important; }
#chat_msg { width: auto !important; height: 350px; padding: 2px; }
#volume + b { display: block; font-size: 0.75em; }
#app > p:not(#error) { visibility: hidden; }
#black { visibility: visible; color: white; }
#black::before { content: 'ТБ: '; }
.small { padding: 0 5px; background-color: #ffdead; font-size: 15px; }
#history_block > div { visibility: hidden; }
#location { visibility: visible; position: fixed; right: 15px; top: 5px; z-index: 5; padding: 0 5px; font-weight: bold; font-size: 1.5em; background-color: #ffdead; }
h2 { font-size: 1.2em; }
`;
const splitInfo = (getSettings(CONF_CW3_COMPACT_SPLIT_INFO));
const sticky = (getSettings(CONF_CW3_COMPACT_SPLIT_INFO_STICKY_HEADERS));
if (isDesktop) css += `
#chat_form { grid-template-columns: auto auto; }
#info_main > tbody > tr { display: grid; max-height: 1000px; grid-template-areas: 'parameter' 'history' 'family'; grid-template-rows: ${splitInfo ? '252px 1fr 1fr' : 'auto auto auto'}; grid-row-gap: 5px; }
#family.infos { grid-area: family; overflow: auto; }
#history.infos { grid-area: history; overflow: auto; }
#parameter.infos { grid-area: parameter; overflow: auto; }
`;
else css += `
#chat_form { grid-template-columns: auto auto auto; }
#info_main > tbody { display: grid; max-height: 1000px; grid-template-areas: 'parameter' 'history' 'family'; grid-template-rows: ${splitInfo ? '252px 1fr 1fr' : 'auto auto auto'}; grid-row-gap: 5px; }
#info_main > tbody > tr:nth-child(1) { grid-area: parameter; overflow: auto; }
#info_main > tbody > tr:nth-child(2) { grid-area: history; overflow: auto; }
#info_main > tbody > tr:nth-child(3) { grid-area: family; overflow: auto; }
`;
const hideHeaders = (getSettings(CONF_CW3_COMPACT_HIDE_HEADERS));
if (hideHeaders) {
css += `
#info_main h2 { visibility: hidden; }
#parameters-alert { visibility: visible; }
`;
}
else if (splitInfo && sticky) {
css += `#info_main h2 { position: sticky; }`;
}
const swap = (getSettings(CONF_CW3_COMPACT_SWAP_SIDES));
const chatup = (getSettings(CONF_CW3_COMPACT_CHAT_ON_TOP));
if (swap && chatup) {
css += `#main_table > tbody { grid-template-areas: 'info field tos' 'info field chat' 'info field actions' 'info field mouth'; grid-template-rows: 25px 425px 267.5px 267.5px; }`;
}
else if (swap && !chatup) {
css += `#main_table > tbody { grid-template-areas: 'info field tos' 'info field actions' 'info field mouth' 'info field chat'; grid-template-rows: 25px 267.5px 267.5px 425px; }`;
}
else if (!swap && chatup) {
css += `#main_table > tbody { grid-template-areas: 'tos field info' 'chat field info' 'actions field info' 'mouth field info'; grid-template-rows: 25px 425px 267.5px 267.5px; }`;
}
else {
css += `#main_table > tbody { grid-template-areas: 'tos field info' 'actions field info' 'mouth field info' 'chat field info'; grid-template-rows: 25px 267.5px 267.5px 425px; }`;
}
if (getSettings(CONF_CW3_COMPACT_ROUND_EDGES)) {
css += `.small, #tos, #tr_chat, #tr_actions > td, #tr_mouth > td, #location, #tr_field, #parameter, #cages_div { border-radius: 15px; }`;
if ($('#app').data('mobile') === 1) css += `#info_main > tbody > tr { border-radius: 15px; }`;
else css += `#family, #history{ border-radius: 15px; }`;
}
}
const styleTemplate = `
#error { background-color: var(--error-bg) !important; color: var(--error-color) !important; }
#main_table { background: var(--main-bg) }
#tr_field { background: black !important; }
hr { border: none; border-bottom: 1px solid var(--hr-color) !important; }
body { background-color: var(--body-bg) !important; color: var(--text-color) !important; }
a, a:hover { color: var(--a-color); }
#tr_chat, #tr_actions, #tr_mouth, #info_main { background: none !important; }
.small, #app > p:not(#error), #info_main > tbody > tr > td, #history_block > div, #tr_mouth > td, #tr_actions > td, #location, #black, #tr_chat { background-color: var(--table-bg) !important; color: var(--text-color) !important; border: none !important; }
.myname { background: var(--myname-bg) !important; color: var(--myname-color) !important; }
input, select { background-color: var(--input-bg) !important; color: var(--input-color) !important; border: 1px solid var(--input-border-color) !important; }
.ui-slider { background: var(--input-bg) !important; border: 1px solid var(--input-border-color) !important; }
.ui-slider .ui-slider-handle { background: var(--handle-bg) !important; border: 1px solid var(--input-border-color) !important; }
.hotkey { background: white !important; }
.move_name, #fightLog, #timer, .hotkey { color: #000 !important; }
`;
const theme = getSettings(CONF_CW3_THEME);
const themes = {
'dark_grey': `:root { --table-bg: #222; --error-bg: #3c1e1e; --error-color: #ccc; --main-bg: #222; --hr-color: #282828; --body-bg: #191919; --text-color: #b2b2b2; --a-color: #b2b2b2; --myname-color: black; --myname-bg: #a73; --input-bg: #111; --handle-bg: #383838; --input-color: #aaa; --input-border-color: #282828; }`
, 'black_glass': `:root { --table-bg: #000d; --error-bg: #3c1e1e; --error-color: #ccc; --main-bg: none; --hr-color: #000; --body-bg: #4d4e4f; --text-color: #b2b2b2; --a-color: #b2b2b2; --myname-color: black; --myname-bg: #a73; --input-bg: #111; --handle-bg: #333; --input-color: #ccc; --input-border-color: #000; }`
};
if (theme !== 'default') {
css += themes[theme] + styleTemplate;
}
addCSS(css);
if (getSettings(CONF_CW3_BACKGROUND) !== 'default') {
const bgSize = getSettings(CONF_CW3_BACKGROUND_SIZE);
const bgPos = getSettings(CONF_CW3_BACKGROUND_POSITION);
addCSS(`body { background-size: ${bgSize}; background-position: ${bgPos}; }`);
if (getSettings(CONF_CW3_BACKGROUND) === 'location') {
body.css('background-image', $('#cages_div').css('background-image'));
const cagesDivObserver = new MutationObserver(function (mutations) {
mutations.forEach(function () {
body.css('background-image', $('#cages_div').css('background-image'));
});
});
cagesDivObserver.observe($('#cages_div')[0], { attributes: true });
const pageObserver = new MutationObserver(function (mutations) {
mutations.forEach(function() {
if (body.text() === 'Вы открыли новую вкладку с Игровой, поэтому старая (эта) больше не работает.') {
body.css('background-image', 'none');
cagesDivObserver.disconnect();
pageObserver.disconnect();
}
});
});
pageObserver.observe(document.body, { childList: true });
}
else {
addCSS(`body { background-image: url(${getSettings(CONF_CW3_BACKGROUND_IMAGE)}); }`);
}
}
if (getSettings(CONF_CW3_WEATHER_SNOW)) {
const skyObserver = new MutationObserver(function (mutations) {
let sky = $('#sky').css('background-image').match(/\d+/g)[1];
let isSnow = false;
if (sky === '7' || sky === '8') {
isSnow = true;
setTimeout(function runSnow() {
snow();
if (isSnow) setTimeout(runSnow, 250);
}, 250);
}
mutations.forEach(function () {
if (!$('#snow').length) body.prepend('<div id="snow"></div>');
const weatherObserver = new MutationObserver(function (mutations) {
mutations.forEach(function () {
sky = $('#sky').css('background-image').match(/\d+/g)[1];
if ((sky === '7' || sky === '8') && !isSnow) {
isSnow = true;
setTimeout(function runSnow() {
snow();
if (isSnow) setTimeout(runSnow, 250);
}, 250);
} else {
isSnow = false;
}
});
});
weatherObserver.observe($('#sky')[0], { attributes: true });
skyObserver.disconnect();
});
});
skyObserver.observe($('#main_table > tbody')[0], { childList: true });
}
const cagesObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
const node = mutation.addedNodes[0];
if (!node) return;
if (node.nodeType !== Node.ELEMENT_NODE) return;
if (isDesktop && getSettings(CONF_CW3_COMPACT)) {
if (node.classList.contains('catWithArrow')) {
let padding = 0;
$('#cages').children('tbody').children('tr').last().children().each(function () {
const tooltip = $(this).find('.cat_tooltip');
if (tooltip.length && tooltip.height() > padding) {
padding = tooltip.height();
}
});
padding += 50;
body.css('padding-bottom', padding + 'px')
}
}
if (getSettings(CONF_CW3_LOWER_CATS) && getSettings(CONF_CW3_LOWER_ARROWS)) {
let arrow;
if (node.classList.contains('catWithArrow')) {
arrow = $(node).children('div').children('.arrow');
}
else if (mutation.target.classList.contains('catWithArrow')) {
arrow = $(node).children('.arrow');
}
else return;
if (!arrow.length) return;
const oldTop = Number(getNumber(arrow.css('top')));
const catHeight = Number(getNumber(arrow.children('table').css('width')));
const newTop = oldTop + 150 - catHeight * 1.5;
arrow.css('top', newTop + 'px');
}
});
});
$('.cage_items').each(function () {
cagesObserver.observe(this, { childList: true, subtree: true });
});
if (getSettings(CONF_CW3_ACT_END_IN_TITLE) || getSettings(CONF_CW3_ACT_END_ALERT)) {
const changeTitle = getSettings(CONF_CW3_ACT_END_IN_TITLE);
const blurOnly = getSettings(CONF_CW3_ACT_END_ALERT_BLUR_ONLY);
const audio = new Audio();
audio.src = getSettings(CONF_CW3_ACT_END_ALERT_SOUND);
audio.volume = getSettings(CONF_CW3_ACT_END_ALERT_VOLUME);
let isWindowActive = true;
window.addEventListener('focus', function (event) {
isWindowActive = true;
if (blurOnly) {
audio.pause();
audio.currentTime = 0;
}
});
window.addEventListener('blur', function (event) {
isWindowActive = false;
});
const deysObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.target.id === 'block_mess' && !$('#sek').length) {
if (changeTitle) document.title = 'Игровая / CatWar';
}
else if (mutation.target.id === 'sek' && mutation.addedNodes.length) {
const timeLeft = $('#sek').text();
if (changeTitle) document.title = timeLeft;
if (getSettings(CONF_CW3_ACT_END_ALERT)) {
const alertTime = new RegExp('^' + getSettings(CONF_CW3_ACT_END_ALERT_TIME) + ' .?с');
if (alertTime.test(timeLeft) && (!isWindowActive || !blurOnly || $('#cwmod-popup-wrap').css('display') === 'flex')) {
audio.play();
}
}
}
});
});
deysObserver.observe($('#block_mess')[0], { childList: true, subtree: true });
}
const DiseasesLevels = {};
DiseasesLevels.dirt = ['грязные лапы', 'грязевые пятна', 'клещи', 'блохи'];
DiseasesLevels.wound = ['царапины', 'лёгкие раны', 'глубокие раны', 'смертельные раны'];
DiseasesLevels.drown = ['cсадины', 'лёгкие порезы', 'глубокие царапины', 'смертельные травмы'];
DiseasesLevels.trauma = ['ушибы', 'лёгкие переломы', 'сильные переломы', 'смертельные переломы'];
let catInfos = [];
body.on('mouseenter', '.cat', function () {
const cat = $(this);
const catEl = cat.find('.d');
if (!catEl.length) return;
if (getSettings(CONF_CW3_CAT_INFO)) {
const html = cat.html();
const link = cat.find('a').first();
const catName = link.text();
const catId = /\d+/.exec(link.attr('href'))[0];
const sex = (/Его запах/.exec(html));
const catElHtml = catEl.parent().html();
let height = catEl.css('background-size');
if (height === '101%') height += ' (надута)';
const image = /composited\/([\da-f]{16})\.png/.exec(catElHtml)[1];
let dirt = /dirt\/(\d)/.exec(catElHtml);
let wound = /wound\/(\d)/.exec(catElHtml);
let drown = /drown\/(\d)/.exec(catElHtml);
let trauma = /trauma\/(\d)/.exec(catElHtml);
wound = wound ? Number(wound[1]) : false;
dirt = dirt ? Number(dirt[1]) : false;
drown = drown ? Number(drown[1]) : false;
trauma = trauma ? Number(trauma[1]) : false;
const poisoning = (/poisoning/.exec(catElHtml));
const disease = (/disease/.exec(catElHtml));
const beddings = (/costume\/295\.png/.exec(catElHtml));
let text = `<div style="background: bottom right / 45px no-repeat url(composited/${image}.png);">`;
text += `<a href="/cat${catId}"><b>${catName}</b></a> (ID ${catId})<br><a target="_blank" href="/cw3/composited/${image}.png">Окрас</a>`;
text += `<br>Рост: ${height}`;
text += dirt ? `<br>Грязь ${dirt} степени (${DiseasesLevels.dirt[dirt - 1]})` : '';
text += beddings ? `<br>Убирает подстилки` : '';
text += (wound || drown || trauma || poisoning || disease) ? `<br>Болезни:` : `<br>Здоров` + (sex ? '' : 'а');
text += wound ? `<br>— Раны ${wound} степени (${DiseasesLevels.wound[wound - 1]})` : '';
text += drown ? `<br>— Травмы от утопления ${drown} степени (${DiseasesLevels.drown[drown - 1]})` : '';
text += trauma ? `<br>— Переломы ${trauma} степени (${DiseasesLevels.trauma[trauma - 1]})` : '';
text += poisoning ? `<br>— Отравление` : '';
text += disease ? `<br>— Насморк` : '';
text += `</div>`;
catInfos[catId] = text;
if (!cat.find('.show-more').length) cat.find('.online').before(`<a class="show-more" href="#" data-id="${catId}">Подробнее</a><br>`);
else cat.find('.show-more').data('id', catId);
}
if (getSettings(CONF_CW3_MODIFY_INVENTORY)) {
let things = {};
let cats = [];
let mouth = cat.find('.mouth:not(.new-mouth)').first();
if (mouth.length) {
let newMouth = mouth.siblings('.new-mouth');
if (!newMouth.length) {
mouth.after('<ol class="mouth new-mouth"></ol>');
newMouth = mouth.siblings('.new-mouth');
}
else newMouth.show();
let mouthThings = mouth.children('li');
mouthThings.each(function () {
const li = $(this);
if (li.find('div').length) {
cats.push(li.html());
}
else {
let thingId = /\d+/.exec(li.children('img').attr('src'))[0];
if (li.text() !== '') {
things[thingId] = Number(li.text().slice(1));
}
else if (things[thingId]) {
things[thingId]++;
}
else things[thingId] = 1;
}
});
let newMouthHtml = '';
Object.keys(things).forEach(function (key) {
let len = things[key] > 1 ? `×${things[key]}` : '';
newMouthHtml += `<li><img src="things/${key}.png">${len}</li>`;
});
cats.forEach(function (cat) {
newMouthHtml += `<li>${cat}</li>`;
});
mouth.hide();
newMouth.html(newMouthHtml);
}
else cat.find('.new-mouth').hide();
}
});
if (getSettings(CONF_CW3_CAT_INFO)) {
body.on('click', '.show-more', function (e) {
e.preventDefault();
showCwmodPopup('alert', catInfos[$(this).data('id')]);
});
}
if (getSettings(CONF_CW3_PARAMETERS_INFO)) {
$('#parameter').children('h2').first().append(' <a id="parameters-alert" href="#" title="Параметры подробно">+</a>');
$('#parameters-alert').click(function () {
let params = ['Сонливость', 'Голод', 'Жажда', 'Нужда', 'Здоровье', 'Чистота'];
let text = '<center><b>Параметры</b></center>';
['dream', 'hunger', 'thirst', 'need', 'health', 'clean'].forEach(function (param, i) {
const isDream = (param === 'dream'),
isHunger = (param === 'hunger'),
isThirst = (param === 'thirst'),
isNeed = (param === 'need'),
isClean = (param === 'clean');
text += `<br><b>${params[i]}</b><br>`;
let red = parseInt($('#' + param).find("td").last()[0].style.width);
if (Number.isNaN(red)) text += 'Ошибка, попробуйте снова';
else if (red === 0) {
if (isDream && $('.dey[data-id="1"]').length) text += `<span style="color: darkred">100 %</span><br>10 c сна`;
else if (isThirst && $('.dey[data-id="5"]').length) text += `<span style="color: darkred">100 %</span><br>До 30 c питья`;
else if (isNeed && $('.dey[data-id="4"]').length) text += `<span style="color: darkred">100 %</span><br>10 c дел в грязном месте`;
else text += '100 %';
}
else if (red === 150) {
text += '<span style="color: darkred">0 %</span>';
if (isDream) text += `<br>${secToTime(150 * 20)} сна или более`;
if (isThirst) text += `<br>${secToTime(150 * 60 - 30)} питья или более`;
if (isNeed) text += `<br>${secToTime(150 * 30 - 10)} дел в грязном месте или более`;
}
else {
const percent = isClean ? Math.floor((150 - red) / 1.5) : Math.round((150 - red) / 1.5 * 100) / 100;
text += `<span style="color: darkred">${percent}%</span> (−${red}px)`;
if (isDream) {
const maxTime = red * 20 + 10;
text += `<br>До ${secToTime(maxTime)} сна`;
}
else if (isHunger) {
const time = Math.ceil((100 - percent) * 9 / 100) * 15;
text += `<br>${secToTime(time)} поглощения пищи`;
}
else if (isThirst) {
const maxTime = red * 60 + 30;
text += `<br>До ${secToTime(maxTime)} питья`;
}
else if (isNeed) {
const maxTime = red * 30 + 10;
text += `<br>До ${secToTime(maxTime)} дел в грязном месте`;
}
else if (isClean && red <= 75) {
text += `<br>Вылизываться ${secToTime((100 - percent) * 100)}`;
}
}
});
showCwmodPopup('alert', text);
});
}
}
function snow() {
const id = Date.now()
, flake = 'https://porch.website/cwmod/snow/' + Math.ceil(Math.random() * 20) + '.png'
, pos_x = Math.ceil(Math.random() * 98)
, end_x = pos_x + Math.floor(Math.random() * 31) - 15
, deg = Math.ceil(Math.random() * 358)
, width = Math.ceil(Math.random() * 45) + 5
, img = `
<img id="snow_${id}" style="
left: ${pos_x}%;
top: -10%;
position: fixed;
pointer-events: none;
z-index: 72000;
transform: rotate(${deg}deg);
max-width: ${width}px;
" src="${flake}">`
, timefall = Math.ceil(Math.random() * 12000) + 5000;
$("#snow").append(img);
$(`#snow_${id}`).animate({
top: '120%',
left: end_x + '%'
}, timefall, function () {
$(`#snow_${id}`).empty().remove();
});
}
function changeFaePage() {
if (getSettings(CONF_FAE_SHOW_NOTES)) {
const observer = new MutationObserver(function (mutations) {
mutations.forEach(function () {
$('.cat_span').each(function () {
const t = $(this);
const catId = getNumber(t.children().first().attr('href'));
const noteText = getNoteByCatId(catId);
if (noteText) {
t.append(` <span id="${catId}" class="note" style="font-size: 0.9em"></span>`);
$('#' + catId).text(noteText);
}
});
});
});
observer.observe(document.querySelector('#friendList'), { childList: true });
}
if (getSettings(CONF_CAT_ENABLE_NOTES)) {
$(isDesktop ? '#branch' : '#site_table').append(`<b>Список заметок</b><br>`);
let html = '';
const notes = JSON.parse(window.localStorage.getItem('cwmod_notes') || '{}');
Object.keys(notes).forEach(function(catId) {
html += `<tr><td>${catId}</td><td id="note-${catId}"></td><td>${notes[catId]}</td></tr>`;;
});
if (html.length) {
$(isDesktop ? '#branch' : '#site_table').append(`<table><thead><tr><td>ID</td><td>Имя</td><td>Заметка</td></tr></thead><tbody>${html}</tbody></table>`);
Object.keys(notes).forEach(catId => setCatName(catId, '#note-'+catId));
}
else {
$(isDesktop ? '#branch' : '#site_table').append(`<i>Нет заметок об игроках</i>`);
}
}
}
function changeIdeasPage() {
addCSS(`.vote[style="color:#000"] { color: inherit !important; } .idea { color: black; } .idea a, .idea a:hover { color: #005 !important; }`);
}
function changeIndexPage() {
let css = `
#act_name b { color: black; }
#info { color: black; background: rgba(255, 255, 255, 0.5); }
#clan_icon, #age_icon, #age2_icon, #act_icon { cursor: pointer; }
#cwmod-grats { width: fit-content; padding: 5px; background: rgba(255, 255, 255, 0.5); border-radius: 10px; }
`;
if (getSettings(CONF_INDEX_EDUCATION_HIDE)) {
css += `#education, #education-show, #education-show + br {display: none !important}`;
}
addCSS(css);
addBBcode();
const catId = $('[src="img/icon_id.png"]').parent().siblings().children('a').children('b').text();
activityCalc(catId);
moonCalc();
if (getSettings(CONF_INDEX_SAVE_ALERT)) addSaveAlert();
}
function activityCalc(catId) {
const actStages = [
{ name: 'пустое место', fromZero: -5000 }
, { name: 'подлежащий удалению', fromZero: -5000 }
, { name: 'покинувший игру', fromZero: -2000 }
, { name: 'забывший про игру', fromZero: -1000 }
, { name: 'забытый кот', fromZero: -750 }
, { name: 'ужаснейшая', fromZero: -500 }
, { name: 'ужасная', fromZero: -300 }
, { name: 'ухудшающаяся', fromZero: -150 }
, { name: 'отрицательная', fromZero: -50 }
, { name: 'переходная', fromZero: -5 }
, { name: 'положительная', fromZero: 5 }
, { name: 'улучшающаяся', fromZero: 50 }
, { name: 'замечательная', fromZero: 150 }
, { name: 'переход 2 мин 15 с', fromZero: 225 }
, { name: 'замечательнейшая', fromZero: 300 }
, { name: 'переход 2 мин', fromZero: 450 }
, { name: 'любимый кот', fromZero: 500 }
, { name: 'переход 1 мин 45 с', fromZero: 675 }
, { name: 'легенда сайта', fromZero: 750 }
, { name: 'переход 1 мин 30 с', fromZero: 900 }
, { name: 'ходячий миф', fromZero: 1000 }
, { name: 'переход 1 мин 15 с', fromZero: 1125 }
, { name: 'переход 1 мин', fromZero: 1350 }
, { name: 'переход 45 c', fromZero: 1575 }
, { name: 'император Игровой', fromZero: 2000 }
, { name: 'частичка Игровой', fromZero: 5000 }
, { name: 'хранитель Игровой', fromZero: 20000 }
, { name: 'идеальная', fromZero: 75000 }
, { name: 'сверхидеальная', fromZero: 150000 }
];
const sets = JSON.parse(window.localStorage.getItem('cwmod_act') || '{}');
if (!sets[catId]) {
sets[catId] = {};
if (window.localStorage.getItem('cwm_hours') !== null) {
sets[catId].hours = Number(window.localStorage.getItem('cwm_hours'));
window.localStorage.removeItem('cwm_hours');
}
else sets[catId].hours = 24;
sets[catId].opened = true;
}
/// до 2.2
if (sets[catId].actgoal) {
actStages.forEach(function (stage, i) {
if (i && Number(sets[catId].actgoal) === stage.fromZero) {
sets[catId].goal = i;
delete sets[catId].actgoal;
}
});
}
function updateHourWord() {
const hours = sets[catId].hours;
$('#hour-word').text(declOfNum(hours, ['час', 'часа', 'часов']));
}
function actLength(d) {
const minus = sets[catId].minus || 0;
if (d <= 14) return 150 - minus;
else if (d >= 1575) return 45 - minus;
else return Math.ceil(150 - d / 15) - minus;
}
function left(currentActivity, goal, hoursPerDay) {
const secsPerDay = convertTime('h s', hoursPerDay);
if (actLength(currentActivity) * 4 + 1 > secsPerDay) {
return { actions: '∞', time: '∞', date: 'никогда' };
}
const actionsWithoutDecr = goal - currentActivity;
let days = 0;
let secsToday;
while (currentActivity < goal) {
secsToday = 0;
while (secsToday < secsPerDay) {
currentActivity++;
secsToday += actLength(currentActivity);
if (currentActivity >= goal) break;
}
if (currentActivity >= goal) break;
days++;
currentActivity -= 4.8;
}
const actionsDecr = Math.floor(days * 4.8 + convertTime('s h', secsToday) / 5);
const time = secsPerDay * days + secsToday;
const now = new Date();
const tomorrow = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
const secsToTomorrow = convertTime('ms s', tomorrow - now);
if (days === 0 && secsToday > secsToTomorrow) days++;
const date = new Date(Date.now() + convertTime('d ms', days));
return {
actions: actionsWithoutDecr + actionsDecr,
time: secToTime(time),
date: date.getDate() + ' ' + months[date.getMonth()] + ' ' + date.getFullYear()
};
}
function updateToact() {
if (progress.stage === actStages.length - 1) {
$('#toact').hide();
return;
}
const goal = Number($('#act-list').val());
const result = left(progress.doneFromZero, actStages[goal].fromZero, sets[catId].hours);
$('#toact > ul').html(`
<li>${result.actions} ${declOfNum(result.actions, ['переход', 'перехода', 'переходов'])} (${result.time})</li>
<li>будет достигнута ${result.date}</li>
`);
}
const act = $('#act_name b').text().split(' (');
const progress = {};
actStages.forEach(function (stage, i) {
if (act[0] === stage.name) {
progress.doneFromZero = stage.fromZero + Number(act[1].split('/')[0]);
}
if (
(!actStages[i + 1] || actStages[i + 1].fromZero > progress.doneFromZero)
&& actStages[i].fromZero <= progress.doneFromZero
) {
progress.stage = i;
}
});
const actInfoHTML = `
<details id="calc-act"${sets[catId].opened ? ' open' : ''}>
<summary id="open-calc"><b>Калькулятор активности</b></summary>
<p id="cwmod-grats" style="display:none"></p>
<div id="actlength"><b>Переход</b>: ${secToTime(actLength(progress.doneFromZero))}</div>
<div>Предметы во рту уменьшают мой переход <nobr>на
<select id="minus">
<option value="0">0 секунд</option>
<option value="2">2 секунды</option>
<option value="4">4 секунды</option>
<option value="6">6 секунд</option>
</select></nobr>
</div>
<div>Я качаю активность <input id="hours-per-day" type="number" step="0.25" min="0" max="24"
value="${sets[catId].hours}" style="width: 60px"> <span id="hour-word"></span> в сутки</div>
<div id="toact">
<b>Цель: <select style="display: inline" id="act-list"></select></b>:
<ul style="margin: 0.5em"></ul>
</div>
<div>Переход начнёт падать <span id="tofall"></span></div>
</details>
`;
$('#info').after(actInfoHTML);
for (let i = progress.stage + 1; i < actStages.length; i++) {
$('#act-list').append(`<option value="${i}">${actStages[i].name}</option>`);
}
if (sets[catId].goal > progress.stage || sets[catId].noGrats) {
$(`#act-list > [value="${sets[catId].goal}"]`).prop('selected', true);
}
else if (sets[catId].goal) {
$(`#cwmod-grats`).html(`
Цель <b>«${actStages[sets[catId].goal].name}»</b> достигнута!
<center><img src="/img/stickers/systempaw3/6.png"></center>
<input id="cwmod-grats-hooray" type="button" value="Скрыть">
<br><input id="cwmod-grats-never-show" type="checkbox"> Больше не поздравлять на этом персонаже
`).show();
$('#cwmod-grats-hooray').click(function () {
$(`#cwmod-grats`).hide(200);
$(`#cwmod-grats`).hide(200);
sets[catId].goal = Number($('#act-list').val());
sets[catId].noGrats = $('#cwmod-grats-never-show').is(':checked');
saveData('act', sets);
});
}
if (sets[catId].minus) {
$(`#minus > [value="${sets[catId].minus}"]`).prop('selected', true);
}
updateHourWord();
updateToact();
if (actLength(progress.doneFromZero) !== 45) {
$('#tofall').parent().hide();
}
else {
const timeFall = new Date(Date.now() + (progress.doneFromZero - 1575) * 5 * 3600000);
$('#tofall').html(
timeFall.getDate() + ' '
+ months[timeFall.getMonth()]
+ ' ' + timeFall.getFullYear()
);
}
$('#minus').change(function () {
sets[catId].minus = $(this).val();
saveData('act', sets);
updateToact();
$('#actlength').html(`<b>Переход</b>: ${secToTime(actLength(progress.doneFromZero))}`);
});
$('#act-list').change(function () {
sets[catId].goal = Number($('#act-list').val());
saveData('act', sets);
updateToact();
});
$('#hours-per-day').on('input', function () {
const hours = Number($('#hours-per-day').val());
if (hours < 0 || hours > 24 || !Number.isInteger(hours * 1000)) {
$('#hours-per-day').val(sets[catId].hours);
return;
}
sets[catId].hours = hours;
saveData('act', sets);
updateHourWord();
updateToact();
});
$('#open-calc').click(function () {
sets[catId].opened = !$('#calc-act').is('[open]');
saveData('act', sets);
});
}
function changeKnsPage() {
if (getSettings(CONF_KNS_SAVE_ALERT)) addSaveAlert();
}
function changeLsPage() {
addCSS(`
.msg_header { font-size: 1.2rem; text-align: center; }
#search, #saved { display: none; }
label { cursor: pointer; }
.msg_deleted { color: darkred; }
.messList { background-color: ${$('#messList').css('background-color')}; color: ${$('#messList').css('color')}; }
.messList a { color: #0000cd; }
`);
const enableSaving = getSettings(CONF_LS_ENABLE_SAVING);
if (enableSaving) $('#links').append(` | <a href="ls?3" id="f3">Сохранённые (<span id="saved-number">?</span>)</a>`);
$('#links').append(` | <a href="ls?search" id="s">Поиск</a>`);
let html = `
<div id="search">
<form class="usn" id="search-form">
<p>
Найти
<label><input name="search-folder" type="radio" value="0"> входящие</label>
<label><input name="search-folder" type="radio" value="1"> отправленные</label>
<label><input name="search-folder" type="radio" value="2"> непрочитанные</label>
</p>
`;
if (enableSaving) html += `
<p>
<label><input name="search-type" id="search-all" type="checkbox"> во всех ЛС на этом персонаже</label>
<label><input name="search-type" id="search-saved" type="checkbox"> в сохранённых ЛС</label>
</p>
`;
html += `
<p>
<input id="search-cat" type="text" placeholder="Имя или ID собеседника">
<input id="search-text" type="text" placeholder="Текст">
<input id="search-ok" type="button" value="ОК">
</p>
</form>
<div id="search-list"></div>
</div>
`;
if (enableSaving) html += '<div id="saved"><div id="saved-list"></div></div>';
$(isDesktop ? '#branch' : '#site_table').append(html);
addSearchFunc(enableSaving);
if (enableSaving) {
updateSavedLsList();
$(window).on('storage', function (e) {
if (e.originalEvent.key === 'cwmod_ls') updateSavedLsList();
});
if (isPage('ls?3')) showSavedLsList();
if (isPage(/^https:\/\/catwar.su\/ls\?id=\d+/)) changeMessagePage();
body.on('click', '.del-saved', function(){
const lsId = $(this).data('id');
const subject = $(this).parent().siblings().first().text();
const catName = $(this).parent().siblings('.cat_name').text();
if (confirm(`Удалить ЛС «${subject}» от игрока ${catName} из сохранённых?`)) {
deleteSavedLs(lsId);
$(this).parent().parent().remove();
}
});
}
if (isPage('ls?search')) showSearch();
if (isPage('ls?new')) addBBcode();
$('a').click(function (e) {
if ($(this).attr('id') === 'f3') {
if (e.ctrlKey) return;
e.preventDefault();
history.pushState(null, null, 'https://catwar.su/ls?3');
showSavedLsList();
}
else if ($(this).attr('id') === 's') {
if (e.ctrlKey) return;
e.preventDefault();
history.pushState(null, null, 'https://catwar.su/ls?search');
showSearch();
}
else {
hideSavedLsList();
hideSearch();
}
});
const observer = new MutationObserver(function (mutations) {
mutations.forEach(function () {
if (enableSaving && isPage('ls?3')) {
history.pushState(null, null, 'https://catwar.su/ls?3');
showSavedLsList();
}
else if (isPage('ls?search')) {
history.pushState(null, null, 'https://catwar.su/ls?search');
showSearch();
}
else {
if (enableSaving) hideSavedLsList();
hideSearch();
}
if (isPage('ls?new')) addBBcode();
if (enableSaving && isPage(/^https:\/\/catwar.su\/ls\?id=\d+/)) changeMessagePage();
});
});
observer.observe($('#main')[0], { childList: true });
body.on('click', '#preview', function(){
if (isDesktop) {
$('#preview_div').after(`
<table border="1" style="width: 90%; max-width: 500px;">
<tbody>
<tr><td id="preview-subject" colspan="2"></td></tr>
<tr>
<td valign="top">
Отправитель: <span id="preview-sender"></span>
<br>Сегодня в <span id="preview-date"></span>
<br>Переписка: <u><big><b>+</b></big></u> …
</td>
<td id="preview-text"></td>
</tr>
</tbody>
</table>
`);
} else {
$('#preview_div').after(`
<table border="1" style="width: 90%; max-width: 500px;">
<tbody>
<tr><td id="preview-subject"></td></tr>
<tr>
<td valign="top">
Отправитель: <span id="preview-sender"></span>
<br>Сегодня в <span id="preview-date"></span>
<br>Переписка: <u><big><b>+</b></big></u> …
</td>
</tr>
<tr><td id="preview-text"></td></tr>
</tbody>
</table>
`);
}
let subject = $('#subject').val().replaceAll('<', '<');
if (!subject) subject = '( = )';
$('#preview-subject').html(subject);
getCurrentUser(function(catId, catName) {
$('#preview-sender').html(`<a href="cat${catId}">${catName}</a>`);
});
const currentDate = new Date();
$('#preview-date').html(`${leadingZero(currentDate.getHours())}:${leadingZero(currentDate.getMinutes())}`);
$('#preview-text').html($('#preview_div'));
});
}
function addSearchFunc(enableSaving) {
const lastSearch = getSettings(CONF_LS_LAST_SEARCH);
const lastFolder = lastSearch.folder;
const lastType = enableSaving ? lastSearch.type : 1;
$(`[name="search-folder"][value="${lastFolder}"]`).prop('checked', true);
switch (lastType) {
case 1:
$('#search-all').prop('checked', true);
break;
case 2:
$('#search-saved').prop('checked', true);
break;
case 3:
$('[name="search-type"]').prop('checked', true);
break;
default:
$('[name="search-type"]').prop('checked', false);
}
$('#search-ok').click(searchLs);
$('[name="search-folder"]').change(function () {
const folder = parseInt($('[name="search-folder"]:checked').val(), 10);
lastSearch.folder = folder;
setSettings(CONF_LS_LAST_SEARCH, lastSearch);
});
$('[name="search-type"]').change(function () {
const searchAll = $('#search-all').is(':checked');
const searchSaved = $('#search-saved').is(':checked');
if (searchAll && !searchSaved) lastSearch.type = 1;
else if (!searchAll && searchSaved) lastSearch.type = 2;
else if (searchAll && searchSaved) lastSearch.type = 3;
else lastSearch.type = 0;
setSettings(CONF_LS_LAST_SEARCH, lastSearch);
});
$('#search-cat').keypress(function (e) {
if (e.which == 13) {
$('#search-text').focus();
return false;
}
});
$('#search-text').keypress(function (e) {
if (e.which == 13) {
searchLs();
return false;
}
});
}
function showSearch() {
$('.active').removeClass('active');
$('#s').addClass('active');
$('#main, #saved').hide();
$('#search').show();
}
function hideSearch() {
$('#main').show();
$('#search').hide();
}
function showSavedLsList() {
$('.active').removeClass('active');
$('#f3').addClass('active');
$('#main, #search').hide();
$('#saved').show();
}
function hideSavedLsList() {
$('#main').show();
$('#saved').hide();
}
function changeMessagePage() {
// if ($('#delete-saved-ls').length) return;
// if ($('.bbcode').length) addBBcode();
// ↑ у меня есть некоторые вопросы к себе
const main = $('#main');
const lsId = parseInt(window.location.href.split('=')[1], 10);
const savedLs = getSavedLsById(lsId);
const btnDelete = `<input id="delete-saved-ls" type="button" value="Удалить" style="float: right">`;
const isLsOnSever = !(main.html() === 'ЛС не найдено.');
if ($('#msg_subject').length && lsId) {
const btnSave = `<input id="savels" type="button" value="Сохранить" style="float: right">`;
const subjectTd = $('#msg_subject');
subjectTd.html(`<span id="msg_subject">${subjectTd.html()}</span>${btnSave}`);
subjectTd.removeAttr('id');
$('#savels').click(saveLs);
if (savedLs) {
const td = $('#msg_table > tbody > tr:last-child > td');
td.html(td.html() + `<i id="savedate">Сохранено ${savedLs.savedate}</i> ${btnDelete}`);
}
}
else if (!isLsOnSever && savedLs) {
insertSavedLs(main, lsId, savedLs, btnDelete);
}
body.on('click', '#delete-saved-ls', function () {
if (isLsOnSever) {
deleteSavedLs(lsId);
$('#savedate').remove();
$('#delete-saved-ls').remove();
}
else if (confirm('Удалить это ЛС из сохранённых?')) {
deleteSavedLs(lsId);
main.html('ЛС не найдено.');
}
});
if ($('#msg_login').length) {
let myId;
if (savedLs) myId = Number(savedLs.myId);
else myId = Number(main.data('id'));
const catId = Number(getNumber($('#msg_login').attr('href')));
const history = JSON.parse(window.localStorage.getItem('cwmod_ls_history') || '{}');
if (!history[myId]) {
history[myId] = {};
}
if (!history[myId][catId]) {
history[myId][catId] = {};
}
$('#msg_info > .msg_open').each(function () {
const id = $(this).data('id');
const isMy = ($(this).text() === '-');
history[myId][catId][id] = isMy;
});
saveData('ls_history', history);
}
}
function insertSavedLs(main, lsId, ls, btnDelete) {
const info = `
${ls.type ? 'Получатель' : 'Отправитель'}: <span id="msg_login" href="/cat${ls.catId}">${ls.catName}</span>
<br>${ls.date}
<br>Переписка: <span id="msg-history"></span>
`;
if (isDesktop) {
main.html(`
<table id="msg_table" border="1">
<tbody>
<tr><td colspan="2">${escapeHTML(ls.subject)}</td></tr>
<tr><td id="msg_info" valign="top">${info}</td><td>${ls.text}</td></tr>
<tr><td colspan="2"><i>${ls.type ? 'Отправитель' : 'Получатель'}: ${ls.myName} [${ls.myId}]<br>Сохранено ${ls.savedate} ${btnDelete}</i></td></tr>
</tbody>
</table>
`);
} else {
main.html(`
<table id="msg_table" border="1">
<tbody>
<tr><td>${escapeHTML(ls.subject)}</td></tr>
<tr><td id="msg_info" valign="top">${info}</td></tr>
<tr><td>${ls.text}</td></tr>
<tr><td><i>${ls.type ? 'Отправитель' : 'Получатель'}: ${ls.myName} [${ls.myId}]<br>Сохранено ${ls.savedate} ${btnDelete}</i></td></tr>
</tbody>
</table>
`);
}
setCatName(ls.catId, `#msg_login`, ls.catName);
const history = JSON.parse(window.localStorage.getItem('cwmod_ls_history'))[ls.myId][ls.catId];
const historyArray = {};
Object.keys(history).forEach(function (key) {
const isMy = history[key];
$('#msg-history').prepend(`<span class="msg_deleted">${isMy ? '-' : '+'}</span> `);
});
Object.keys(history).forEach(function (key) {
const isMy = history[key];
$.post('/ajax/mess_show', {
id: key
}, function (data) {
const isSaved = getSavedLsById(key);
if (isSaved || !data.fail) {
let lsLink = `<a href="ls?id=${key}" class="msg_open" data-id="${key}">`
if (Number(key) === lsId) lsLink += `<big><b>`
lsLink += isMy ? '-' : '+';
if (Number(key) === lsId) lsLink += `</b></big>`
if (Number(key) === lsId) lsLink += `</b></big>`
lsLink += `</a>`
historyArray[key] = lsLink;
}
else {
historyArray[key] = `<span class="msg_deleted">${isMy ? '-' : '+'}</span>`;
}
if (Object.keys(historyArray).length === Object.keys(history).length) {
$('#msg-history').empty();
Object.keys(historyArray).forEach(function (k) {
$('#msg-history').prepend(historyArray[k] + ' ');
});
}
}, 'json');
});
}
function searchLs() {
const folder = parseInt($('[name="search-folder"]:checked').val(), 10);
const searchAll = $('#search-all').is(':checked');
const searchSaved = $('#search-saved').is(':checked');
if (!searchAll && searchSaved && folder === 2) {
$('#search-list').html('<img src="/img/stickers/systempaw2/6.png">');
}
else {
$('#search-list').html(`
<h2>Результаты поиска</h2>
<p>Найдено: <span id="search-number">0</span></p>
<table class="messList">
<tbody id="search-results">
<tr><th>Тема</th><th>${folder === 1 ? 'Получатель' : 'Отправитель'}</th><th>Дата</th></tr>
</tbody>
</table>
`);
const cat = $('#search-cat').val();
let text = $('#search-text').val();
if (text) {
text = text.match(/['_\-а-яёa-z0-9$]+/gi);
text = new RegExp(text.join('|'), 'gi');
}
if (searchAll || !searchSaved) searchAllLs(folder, cat, text);
if (searchSaved || !searchAll) searchSavedLs(folder, cat, text);
}
}
function searchAllLs(type, cat, text) {
getCatIdByName(cat, function (catId) {
$.post('/ajax/mess_folder', {
folder: type,
page: 1,
del: 0
}, function (data) {
const column = (type ? 'poluch' : 'otpr');
for (let i = 1; i <= data.page; i++) {
$.post('/ajax/mess_folder', {
folder: type,
page: i,
del: 0
}, function (data) {
for (let j = 0; j < data.msg.length; j++) {
const msg = data.msg[j];
const id = msg.id;
const html = `
<tr class="${msg.new ? 'msg_read' : 'msg_notRead'}">
<td><a href="ls?id=${msg.id}" class="msg_open" data-id="${msg.id}">${msg.subject}</a></td>
<td><a href="cat${msg[column]}">${msg.login}</a></td>
<td>${msg.time}</td>
</tr>
`;
$.post('/ajax/mess_show', {
id: id
}, function (data) {
if (cat) {
if (catId !== msg[column] && cat !== msg[column] && cat.toLowerCase() !== msg.login.toLowerCase()) return;
}
if (text) {
if (!data.msg.subject.match(text) && !data.msg.text.replace(/<[^>]+>/g, '').match(text)) return;
}
$('#search-results').append(html);
$('#search-number').html($('#search-results').children().length - 1);
}, 'json');
}
}, 'json');
}
}, 'json');
});
}
function searchSavedLs(type, cat, text) {
const savedLs = JSON.parse(window.localStorage.getItem('cwmod_ls'));
if (savedLs) {
getCatIdByName(cat, function (catId) {
for (let key in savedLs) {
const ls = savedLs[key];
if (ls.type !== type) continue;
if (cat) {
if (
catId !== ls.catId
&& cat !== ls.catId
&& cat.toLowerCase() !== ls.catName.toLowerCase()
) {
continue;
}
}
if (text) {
if (
!ls.subject.match(text)
&& !ls.text.replace(/<[^>]+>/g, '').match(text)
) {
continue;
}
}
$.post('/ajax/mess_show', {
id: key
}, function (data) {
if (data.fail) {
const html = `
<tr class="msg_read">
<td><a href="ls?id=${key}" class="msg_open" data-id="${key}">${escapeHTML(ls.subject)}</a></td>
<td class="search-cat-name" data-id="${key}">${ls.catName}</td>
<td>${ls.savedate}</td>
</tr>
`;
$('#search-results').append(html);
$('#search-number').html($('#search-results').children().length - 1);
setCatName(ls.catId, `.search-cat-name[data-id="${key}"]`, ls.catName);
}
}, 'json');
}
});
}
else {
$('#search-results').html('Нет сохранённых сообщений');
}
}
function updateSavedLsList() {
const savedLs = JSON.parse(window.localStorage.getItem('cwmod_ls'));
if (savedLs) {
$('#saved-list').html(`
<h2>Входящие</h2>
<table class="messList">
<tbody id="inboxLsList">
<tr><th>Тема</th><th>Отправитель</th><th>Дата сохранения</th><th>X</th></tr>
</tbody>
</table>
<h2>Отправленные</h2>
<table class="messList">
<tbody id="outboxLsList">
<tr><th>Тема</th><th>Получатель</th><th>Дата сохранения</th><th>X</th></tr>
</tbody>
</table>
`);
const inbox = $('#inboxLsList');
const outbox = $('#outboxLsList');
for (let key in savedLs) {
const ls = savedLs[key];
const html = `
<tr class="msg_read">
<td><a href="ls?id=${key}" class="msg_open" data-id="${key}">${escapeHTML(ls.subject)}</a></td>
<td class="cat_name" data-id="${key}">${ls.catName}</td>
<td>${ls.savedate}</td>
<td><input type="button" value="X" class="del-saved" data-id="${key}"></td>
</tr>
`;
if (ls.type) outbox.append(html);
else inbox.append(html);
setCatName(ls.catId, `.cat_name[data-id="${key}"]`, ls.catName);
}
$('#saved-number').text(Object.keys(savedLs).length);
} else {
$('#saved-number').text(0);
$('#saved-list').html(`Сообщений нет.`);
}
}
function saveLs() {
try {
const savedLs = JSON.parse(window.localStorage.getItem('cwmod_ls') || '{}');
const main = $('#main');
const lsId = parseInt(window.location.href.split('=')[1], 10);
const lsInfo = $('#msg_info').html();
const ls = {};
ls.subject = $('#msg_subject').text();
ls.text = $('#msg_table').find('.parsed').html();
ls.date = findDate(lsInfo);
ls.catId = parseInt(getNumber($('#msg_login').attr('href')), 10);
ls.catName = $('#msg_login').html();
ls.myId = main.data('id');
ls.myName = main.data('login');
ls.type = lsInfo.match(/Получатель/) ? 1 : 0;
const now = new Date();
const saveDate = {};
saveDate.day = leadingZero(now.getDate());
saveDate.month = leadingZero(now.getMonth() + 1);
saveDate.year = now.getFullYear();
saveDate.hour = leadingZero(now.getHours());
saveDate.minute = leadingZero(now.getMinutes());
saveDate.second = leadingZero(now.getSeconds());
ls.savedate = `${saveDate.year}-${saveDate.month}-${saveDate.day} ${saveDate.hour}:${saveDate.minute}:${saveDate.second}`;
savedLs[lsId] = ls;
saveData('ls', savedLs);
if ($('#savedate').length) $('#savedate').text(`Сохранено ${ls.savedate}`);
else {
const td = $('#msg_table > tbody > tr:last-child > td');
td.append(`<i id="savedate">Сохранено ${ls.savedate}</i> <input id="delete-saved-ls" type="button" value="Удалить" data-id="${lsId}" style="float: right">`);
$('#saved-number').text(Number($('#saved-number').text()) + 1);
}
updateSavedLsList();
} catch (err) {
window.console.error('Варомод:', err);
}
}
function deleteSavedLs(lsId) {
try {
const savedLs = JSON.parse(window.localStorage.getItem('cwmod_ls'));
if (!savedLs) return;
delete savedLs[lsId];
saveData('ls', savedLs);
} catch (err) {
window.console.error('Варомод:', err);
}
}
function getSavedLsById(lsId) {
try {
const savedLs = JSON.parse(window.localStorage.getItem('cwmod_ls'));
if (!savedLs) return;
const ls = savedLs[lsId];
return ls || false;
} catch (err) {
window.console.error('Варомод:', err);
}
}
/*
function changeTimePage() {
const catTimeNow = timestampToCatTime(Date.now());
$(isDesctop ? '#branch' : '#site_table').append(`
<div style="width: fit-content; margin: 0 auto">
<p><b>Настоящее кошачье время</b></p>
<p id="real-cat-time">${catTimeNow.day} ${months[catTimeNow.month]} ${catTimeNow.year} года, ${leadingZero(catTimeNow.hour)}:${leadingZero(catTimeNow.minute)}:${leadingZero(catTimeNow.second)}</p>
<p><b>Калькулятор времени</b></p>
<p>Кошачье время: <input type="number" id="cat-day" min="1" max=""> <input type="time" id="cat-time"></p>
<p>Время двуногих: <input type="datetime-local" id="twoleg-time" min="${dateToString(catTimeStart)}" value="${dateToString(new Date)}" max="9999-31-12T23:59"></p>
</div>
`);
}
*/
function changeSettingsPage() {
let css = `
.copy { cursor: pointer; }
#cwmod-settings h2 { text-indent: 1.5em; }
#cwmod-settings h3 { margin: 1em 0 0.5em 1em; }
#cwmod-settings h4 { margin: 0; }
#cwmod-settings ul { margin: 0; padding: 0 0 0 30px; list-style-type: kannada; }
#cwmod-settings ul ul { padding: 0 0 0 10px; list-style-type: none; }
#cwmod-settings li { padding: 0.2em 0; }
.cwmod-settings[type="checkbox"] { margin-left: 0; cursor: pointer; }
.cwmod-data-result { margin-bottom: 1em; max-height: 300px; overflow-y: auto; white-space: pre-line;}
.cwmod-error { font-weight: bold; color: darkred; }
.cwmod-done { font-weight: bold; color: darkgreen; }
`;
addCSS(css);
if (getSettings(CONF_SETTINGS_HIDE_EMAIL)) {
const inputColor = $('input[name="mail"]').css('background-color');
addCSS(`input[name="mail"]:not(:focus) { color: ${inputColor} !important; }`, CONF_SETTINGS_HIDE_EMAIL);
}
const html = `
<div id="cwmod-settings">
<h2 id="cwmod">Настройки Варомода v${VERSION}</h2>
<h3>Сайт</h3>
<h4>Мой кот/моя кошка</h4>
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_INDEX_SAVE_ALERT}"> Предупреждение при уходе со страницы</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_INDEX_EDUCATION_HIDE}"> Скрывать обучение</li>
</ul>
<h4>Профили игроков</h4>
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CAT_ADD_KRAFT_NUMBER}"> Уровень БУ цифрой</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CAT_ENABLE_NOTES}"> Возможность создавать заметки об игроках</li>
</ul>
<h4>Друзья и враги</h4>
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_FAE_SHOW_NOTES}"> Показывать заметки</li>
</ul>
<h4>Личные сообщения</h4>
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_LS_ENABLE_SAVING}"> Возможность сохранять ЛС</li>
</ul>
<h4>Блоги и лента</h4>
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CREATION_SAVE_ALERT}"> Предупреждение при уходе со страницы создания нового блога или поста</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_BLOGS_AVATARS}"> Аватарки в комментариях
<ul data-show="${CONF_BLOGS_AVATARS}">
<li>Размер: <input class="cwmod-settings" type="number" min="30" max="250" style="width: 45px" data-conf="${CONF_BLOGS_AVATARS_SIZE}"> px</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_BLOGS_AVATARS_NO_CROP}"> Не обрезать до квадрата</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_BLOGS_AVATARS_BORDER}"> Рамки у аватарок</li>
</ul>
</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_BLOGS_COMMENTS_SMILES}"> Смайлики в комментариях</li>
<li>Максимальная ширина картинок
<ul>
<li>в блогах: <input class="cwmod-settings" type="number" min="0" max="1000" style="width: 55px" data-conf="${CONF_BLOGS_IMAGES_MAX_WIDTH}"> px</li>
<li>в Ленте: <input class="cwmod-settings" type="number" min="0" max="1000" style="width: 55px" data-conf="${CONF_SNIFF_IMAGES_MAX_WIDTH}"> px</li>
<li><small>0 — значение по умолчанию (не уменьшать)</small></li>
</ul>
</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_BLOGS_ANSWER_BUTTON}"> Кнопка «Ответить на комментарий»</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_BLOGS_CITE_BUTTON}"> Кнопка «Цитировать комментарий»
<ul data-show="${CONF_BLOGS_CITE_BUTTON}">
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_BLOGS_CITE_BUTTON_HIDE}"> Показывать только при выделении текста</li>
</ul>
</li>
</ul>
<h4>Настройки</h4>
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_SETTINGS_HIDE_EMAIL}"> Спрятать адрес электронной почты</li>
</ul>
<h3>Игровая</h3>
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_ACT_END_IN_TITLE}"> Время до окончания действия в заголовке</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_ACT_END_ALERT}"> Звук об окончании действия
<ul data-show="${CONF_CW3_ACT_END_ALERT}">
<li>за <input class="cwmod-settings" type="number" min="1" max="30" style="width: 35px" data-conf="${CONF_CW3_ACT_END_ALERT_TIME}"> с до окончания</li>
<li>Звук: <input class="cwmod-settings" type="text" data-conf="${CONF_CW3_ACT_END_ALERT_SOUND}"> <a href="#" class="cwmod-settings-set-default" data-rel="${CONF_CW3_ACT_END_ALERT_SOUND}">по умолчанию</a></li>
<li>Громкость: <input class="cwmod-settings" type="range" min="0.05" max="1" step="0.05" data-conf="${CONF_CW3_ACT_END_ALERT_VOLUME}"> <a href="#" class="cwmod-settings-test-sound" data-audio="${CONF_CW3_ACT_END_ALERT_SOUND}" data-volume="${CONF_CW3_ACT_END_ALERT_VOLUME}">проиграть</a></li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_ACT_END_ALERT_BLUR_ONLY}"> Только если вкладка неактивна</li>
</ul>
</li>
<li>Высота лога боёв: <input class="cwmod-settings" type="number" min="70" max="1000" style="width: 55px" data-conf="${CONF_CW3_FIGHT_PANEL_HEIGHT}"> px</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_PARAMETERS_INFO}"> Параметры подробно
<br><small>Значения в процентах и в пикселях, примерное время выполнения действий</small>
</li>
</ul>
<h4>Меню</h4>
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_MENU_TARGET_BLANK}"> Открывать в новой вкладке</li>
<li>Добавить пункты:
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_MENU_ABOUT}"> Об игре</li>
<!--<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_MENU_INDEX}"> ${$('.kn1').length ? 'Мой кот' : 'Моя кошка'}</li>-->
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_MENU_TOP}"> СИ (список игроков)</li>
<!--<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_MENU_CHAT}"> Чат</li>-->
<!--<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_MENU_LS}"> ЛС</li>-->
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_MENU_LS0}"> Памятка</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_MENU_BLOGS}"> Блоги</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_MENU_SNIFF}"> Лента</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_MENU_SETTINGS}"> Настройки</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_MENU_MOBILE}"> Сменить версию</li>
</ul>
</li>
</ul>
<h4>Оформление</h4>
<ul>
<li>Тема:
<select class="cwmod-settings" data-conf="${CONF_CW3_THEME}">
<option value="default">По умолчанию</option>
<option value="dark_grey">Тёмно-серая</option>
<option value="black_glass">Полупрозрачная чёрная</option>
</select>
<br><small>Больше тем в <a href="https://porch.website/scripts#cwredesign">Вароредизайне</a>. Не используйте темы Вароредизайна и Варомода одновременно!</small>
</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_COMPACT}"> Компактная игровая ${(($(window).width() < 1500 || $(window).height() < 700) ? ' (не рекомендуется)' : '')}
<ul data-show="${CONF_CW3_COMPACT}">
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_COMPACT_SWAP_SIDES}"> Поменять местами блоки (погода, действия, «во рту», чат справа)</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_COMPACT_CHAT_ON_TOP}"> Чат наверху</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_COMPACT_ROUND_EDGES}"> Скруглить углы</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_COMPACT_SPLIT_INFO}"> Разделить параметры, историю и родственные связи <a href="#" id="about-split-info">(?)</a>
<!--<ul data-show="${CONF_CW3_COMPACT_SPLIT_INFO}">
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_COMPACT_SPLIT_INFO_STICKY_HEADERS}"> Закрепить заголовки</li>
</ul>-->
</li>
</ul>
</li>
<li>Фон страницы:
<select class="cwmod-settings" data-conf="${CONF_CW3_BACKGROUND}">
<option value="default">по умолчанию</option>
<option value="location">фон локации</option>
<option value="own">свой</option>
</select>
<ul data-show="${CONF_CW3_BACKGROUND}" data-cond="own">
<li>Картинка: <input class="cwmod-settings" type="text" data-conf="${CONF_CW3_BACKGROUND_IMAGE}"></li>
</ul>
<ul data-show="${CONF_CW3_BACKGROUND}" data-cond="!default">
<li>Размер:
<select class="cwmod-settings" data-conf="${CONF_CW3_BACKGROUND_SIZE}">
<option value="auto">автоматически</option>
<option value="cover">по размеру страницы</option>
</select>
</li>
<li>Положение:
<select class="cwmod-settings" data-conf="${CONF_CW3_BACKGROUND_POSITION}">
<option value="top left">вверху слева</option>
<option value="top center">вверху по центру</option>
<option value="top right">вверху справа</option>
<option value="center left">по центру слева</option>
<option value="center">по центру</option>
<option value="center right">по центру справа</option>
<option value="bottom left">внизу слева</option>
<option value="bottom center">внизу по центру</option>
<option value="bottom right">внизу справа</option>
</select>
</li>
</ul>
</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_HISTORY_NO_UNDERLINE}"> Не подчёркивать ссылки на профили в истории</li>
</ul>
<h4>Окружающий мир</h4>
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_WEATHER_SNOW}"> Снежинки на странице, когда идет снег</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_HIDE_SKY}"> Скрывать небо</li>
</ul>
<h4>Локация</h4>
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_CAGES_BORDERS}"> Обозначить границы клеток</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_ALWAYS_DAY}"> Всегда день (убрать затемнение игрового поля)</li>
</ul>
<h4>Чат</h4>
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_CHAT_QUIET_LOUDER}"> Увеличивать шрифт тихих звуков</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_CHAT_LOUD_QUIETER}"> Уменьшать шрифт громких звуков</li>
</ul>
<h4>Игроки</h4>
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_LOWER_CATS}"> Опустить котов вниз клеток
<ul data-show="${CONF_CW3_LOWER_CATS}">
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_LOWER_ARROWS}"> Опустить стрелки в боережиме</li>
</ul>
</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_DEAD_OPAQUE}"> Сделать мёртвых игроков непрозрачными</li>
<li>
<input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_CAT_INFO}"> Более подробная информация
<br><small>То, что можно увидеть в кодах: рост, ссылка на окрас, степени грязи и болезней</small>
</li>
<li>
<input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_MODIFY_INVENTORY}"> Сокращать инвентарь
<br><small>Вместо повторения предметов одного типа писать их количество</small>
</li>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_CW3_ADD_REALISM}"> Добавить реализма</li>
</ul>
<h4>Конструктор окрасов</h4>
<ul>
<li><input class="cwmod-settings" type="checkbox" data-conf="${CONF_KNS_SAVE_ALERT}"> Предупреждение при уходе со страницы</li>
</ul>
<p><input id="clear-ym-storage" type="button" value="Кнопка"> для тех, у кого ничего не сохраняется</p>
<div id="clear-ym-storage-result"></div>
<h3>Импорт и экспорт данных</h3>
<details><summary>Как пользоваться</summary>
<ol>
<li>Скопируйте нужные данные в браузере, откуда вы их хотите перенести.</li>
<li>Вставьте их в поле «Импорт» того же раздела в браузере, куда вы их хотите перенести.</li>
<li>Нажмите на кнопку «Объединить» («Обновить» в случае настроек).</li>
</ol>
</details>
<h4>Заметки об игроках</h4>
<p>Экспорт: <input class="cwmod-data-export" data-export="notes" type="text" readonly> <img class="copy" title="Скопировать" alt="Скопировать" data-copy="notes" src="cw3/symbole/copy.png"></p>
<p>Импорт: <input class="cwmod-data-import" data-import="notes" type="text"></p>
<p><input class="cwmod-data-merge" data-merge="notes" type="button" value="Объединить"></p>
<div class="cwmod-data-result" data-result="notes"></div>
<h4>Личные сообщения</h4>
<p>Экспорт: <input class="cwmod-data-export" data-export="ls" type="text" readonly> <img class="copy" title="Скопировать" alt="Скопировать" data-copy="ls" src="cw3/symbole/copy.png"></p>
<p>Импорт: <input class="cwmod-data-import" data-import="ls" type="text"></p>
<p><input class="cwmod-data-merge" data-merge="ls" type="button" value="Объединить"></p>
<div class="cwmod-data-result" data-result="ls"></div>
<h4>Настройки</h4>
<p>Экспорт: <input class="cwmod-data-export" data-export="settings" type="text" readonly> <img class="copy" title="Скопировать" alt="Скопировать" data-copy="settings" src="cw3/symbole/copy.png"></p>
<p>Импорт: <input class="cwmod-data-import" data-import="settings" type="text"></p>
<p><input class="cwmod-data-merge" data-merge="settings" type="button" value="Обновить"></p>
<div class="cwmod-data-result" data-result="settings"></div>
<h3><a href="/blog482084">Блог Варомода</a></h3>
</div>
`;
$(isDesktop ? '#branch' : '#site_table').append(html);
updateSettingsInputs();
try {
$('.cwmod-data-export').each(function () {
const key = $(this).data('export');
$(this).val(window.localStorage.getItem('cwmod_' + key))
});
$(window).on('storage', function (e) {
if (e.originalEvent.key === 'cwmod_settings') {
$('[data-export="notes"]').val(e.originalEvent.newValue);
}
if (e.originalEvent.key === 'cwmod_ls') {
$('[data-export="ls"]').val(e.originalEvent.newValue);
}
});
} catch (err) {
window.console.error('Варомод:', err);
}
$('#about-split-info').click(function (e) {
e.preventDefault();
showCwmodPopup('alert', '<img src="https://porch.website/cwmod/settings.png">');
});
$('.cwmod-data-import').click(function () {
$(this).select();
});
$('.cwmod-data-merge').click(function () {
const key = $(this).data('merge');
mergeData(key);
});
$('.copy').click(function () {
const key = $(this).data('copy');
$(`input[data-export="${key}"]`).select();
document.execCommand('copy');
alert('Скопировано!');
});
$(`[data-conf="${CONF_SETTINGS_HIDE_EMAIL}"]`).change(function () {
if ($(this).is(':checked')) {
addCSS(`input[name="mail"]:not(:focus) { color: #333; }`, CONF_SETTINGS_HIDE_EMAIL);
}
else removeCSS(CONF_SETTINGS_HIDE_EMAIL);
});
$('#clear-ym-storage').click(function () {
try {
window.localStorage.setItem('storage-test', Math.pow(2, 1023).toString(2));
window.localStorage.removeItem('storage-test');
const ymSize = window.localStorage.getItem('_ym_alt_retryReqs').length;
if (ymSize) {
window.localStorage.removeItem('_ym_alt_retryReqs');
$('#clear-ym-storage-result').html(`<p>Возможно, чистка ${ymSize} байт данных Яндекс.Метрики могла помочь.</p>`);
}
}
catch (err) {}
});
}
function mergeData(dataKey) {
$(`[data-result]`).empty();
let exp = $(`[data-export="${dataKey}"]`).val();
let imp = $(`[data-import="${dataKey}"]`).val();
if (!imp) {
mergeDataError(dataKey, null, ['С чем объединять-то?', '<img src="/img/stickers/systempaw2/6.png">']);
return;
}
try {
if (exp) exp = JSON.parse(exp);
} catch (err) {
window.console.error(err);
mergeDataError(dataKey, 'export', ['Ошибка парсинга JSON']);
return;
}
try {
imp = JSON.parse(imp);
} catch (err) {
window.console.error(err);
mergeDataError(dataKey, 'import', ['Ошибка парсинга JSON']);
return;
}
const validExp = mergeDataValidate(dataKey, exp);
if (validExp.error) {
mergeDataError(dataKey, 'export', validExp.text);
return;
}
const validImp = mergeDataValidate(dataKey, imp);
if (validImp.error) {
mergeDataError(dataKey, 'import', validImp.text);
return;
}
let text = [];
const merged = Object.assign({}, exp, imp);
Object.keys(merged).forEach(function (key) {
if (dataKey === 'settings') {
if (DEFAULTS[key] === undefined) {
delete merged[key];
return;
}
}
if (exp[key] && imp[key]) {
if (dataKey === 'ls') {
if (exp[key].catName === imp[key].catName && exp[key].savedate > imp[key].savedate) {
merged[key] = exp[key];
}
}
else if (dataKey === 'notes') {
if (exp[key] === imp[key]) return;
else if (exp[key].indexOf(imp[key]) !== -1) {
merged[key] = exp[key];
text.push(`Заметки об игроке с ID ${key}: "${exp[key]}" и "${imp[key]}" — объединены`);
}
else if (imp[key].indexOf(exp[key]) === -1) {
merged[key] = exp[key] + '\n' + imp[key];
text.push(`Заметки об игроке с ID ${key}: "${exp[key]}" и "${imp[key]}" — объединены в "${merged[key]}"`);
}
}
}
});
console.log(merged);
saveData(dataKey, merged);
$('[data-export="${dataKey}"]').val(JSON.stringify(merged));
mergeDataDone(dataKey, text);
}
function mergeDataValidate(dataKey, data) {
let error = false, text = [];
Object.keys(data).forEach(function (k) {
if (dataKey === 'notes') {
if (!/^\d+$/.test(k)) {
error = true;
text.push(`Ключ _${k}_ не ID игрока`);
}
if (typeof data[k] !== 'string') {
error = true;
text.push(`Элемент _${k}_ не заметка`);
}
}
else if (dataKey === 'ls') {
if (!/^\d+$/.test(k)) {
error = true;
text.push(`Ключ _${k}_ не ID сообщения`);
}
if (typeof data[k] !== 'object') {
error = true;
text.push(`Элемент _${k}_ не сообщение`);
}
else {
const lsKeys = ['subject', 'text', 'type', 'savedate', 'catId', 'catName', 'date', 'myId', 'myName'];
const thisKeys = Object.keys(data[k]);
if (thisKeys.length !== lsKeys.length) {
error = true;
text.push(`Элемент ${k} не сообщение`);
}
else {
let keysError = false;
lsKeys.forEach(function (key) {
if (thisKeys.indexOf(key) === -1) {
keysError = true;
}
});
if (keysError) {
error = true;
text.push(`Элемент ${k} не сообщение`);
}
}
}
}
});
return { error: error, text: text }
}
function mergeDataError(dataKey, type, text = []) {
let errorText = 'Ошибка: ';
const errors = {
'export': 'неправильный формат исходных данных (в порядке всё с ними было, зачем трогать???)'
, 'import': 'неправильный формат входных данных'
};
errorText += errors[type] || 'Неизвестная ошибка';
$(`[data-result="${dataKey}"]`).append(`<p class="cwmod-error">${errorText}</p>${text.join('<br>')}`);
}
function mergeDataDone(dataKey, text = []) {
let resultText = 'Данные успешно объединены';
if (dataKey === 'settings') resultText = 'Настройки успешно обновлены';
$(`[data-result="${dataKey}"]`).append(`<p class="cwmod-done">${resultText}!</p>${text.join('<br>')}`);
}
function updateSettingsInputs() {
Object.keys(DEFAULTS).forEach(function (key) {
const input = $(`[data-conf="${key}"]`);
if (!input.length) return;
const val = getSettings(key);
if (input.is('select')) {
$(`[data-conf="${key}"] > [value="${val}"]`).prop('selected', true);
$(`[data-show="${key}"]`).each(function () {
let cond = $(this).data('cond');
const invert = /^!/.test(cond);
cond = cond.replace(/^!/, '');
if (invert !== (cond === val)) $(this).show();
else $(this).hide();
});
}
else {
const type = input.attr('type');
switch (type) {
case 'text':
case 'number':
case 'range':
input.val(val);
break;
case 'checkbox':
input.prop('checked', val);
if (val) $(`[data-show="${key}"]`).show();
else $(`[data-show="${key}"]`).hide();
break;
default:
window.console.error('я сломался зови хвойницу чинить');
}
}
});
}
function addCSS(css, key) {
const styleId = key ? 'cwmod-style-' + key : 'cwmod-style';
const style = $('#' + styleId);
if (style.length) {
style.append(css);
}
else {
$('head').append(`<style id="${styleId}">${css}</style>`);
}
}
function removeCSS(key) {
$('#cwmod-style-' + key).remove();
}
function getSettings(key) {
thisPageSettings.push(key);
const val = SETTINGS[key];
return val !== undefined ? val : DEFAULTS[key];
}
function setSettings(key, val) {
SETTINGS[key] = val;
saveData('settings', SETTINGS);
}
function loadSettings() {
const key = 'cwmod_settings';
try {
SETTINGS = JSON.parse(window.localStorage.getItem(key) || '{}');
if (SETTINGS['cw3_location_bg'] != null) {
if (SETTINGS['cw3_location_bg']) SETTINGS[CONF_CW3_BACKGROUND] = 'location';
delete SETTINGS['cw3_location_bg'];
}
if (SETTINGS['cw3_location_bg_size'] != null) {
if (SETTINGS['cw3_location_bg_size'] === 'cover') SETTINGS[CW3_BACKGROUND_SIZE] = 'cover';
delete SETTINGS['cw3_location_bg_size'];
}
} catch (err) {
alert(err);
window.localStorage.removeItem(key);
SETTINGS = {};
}
}
function saveData(key, data) {
try {
window.localStorage.setItem('cwmod_' + key, JSON.stringify(data));
} catch (err) {
window.console.error('Варомод:', err);
}
}
function addSaveAlert() {
window.addEventListener('beforeunload', beforeunload);
$('input[type=submit]').click(function () {
window.removeEventListener('beforeunload', beforeunload);
});
}
function beforeunload(event) {
event.preventDefault();
event.returnValue = '';
return '';
}
function isPage(page, match) {
if (page instanceof RegExp) return page.test(window.location.href);
const re = new RegExp('catwar\.su/' + page.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + (match ? '(#.*)?$' : ''));
return re.test(window.location.href);
}
function secToTime(sec) {
if (!sec) return '0 c';
const d = Math.floor(convertTime('s d', sec));
sec -= convertTime('d s', d);
const h = Math.floor(convertTime('s h', sec));
sec -= convertTime('h s', h);
const m = Math.floor(convertTime('s m', sec));
sec -= convertTime('m s', m);
const s = Math.round(sec);
let result = [];
if (d) result.push(`<nobr>${d} д</nobr>`);
if (h) result.push(`<nobr>${h} ч</nobr>`);
if (m) result.push(`<nobr>${m} мин</nobr>`);
if (s) result.push(`<nobr>${s} с</nobr>`);
return result.join(' ');
}
function leadingZero(num) {
return num < 10 ? '0' + num.toString() : num;
}
function escapeHTML(str) {
return str.replace('<', '$lt;').replace('>', '$gt;');
}
function decodeHTML(str) {
const doc = new DOMParser().parseFromString(str, "text/html");
return doc.documentElement.textContent;
}
function getNoteByCatId(catId) {
try {
const savedNotes = JSON.parse(window.localStorage.getItem('cwmod_notes') || '{}');
const text = savedNotes[catId];
return text || false;
} catch (err) {
window.console.error('Варомод:', err);
}
}
function addBBcode(type) {
const bb = $('.bbcode').parent();
if (!bb.length) return;
if ($('.bbcode[data-code="ol"]').length) return;
if (type) {
bb.append(`
<button class="bbcode" title="Перенос" data-code="br" data-parameter="0">br</button>
<button class="bbcode" title="Таблица" data-code="table">table</button>
<button class="bbcode" title="Строка таблицы" data-code="tr">tr</button>
<button class="bbcode" title="Ячейка таблицы" data-code="td">td</button>
<button class="bbcode" title="Нумерованный список" data-code="ol">ol</button>
<button class="bbcode" title="Ненумерованный список" data-code="ul">ul</button>
<button class="bbcode" title="Элемент списка" data-code="li">li</button>
`);
}
else {
$('[data-code="block"]').after(`
<button class="bbcode" title="Раскрывающийся блок" data-code="overblock" data-parameter="1" data-text="Введите название раскрывающегося блока (то же, что и у заголовка, который раскрывает этот блок):">overblock</button>
`);
bb.append(`
<button class="bbcode" title="Абзац" data-code="p">p</button>
<button class="bbcode" title="Перенос" data-code="br" data-parameter="0">br</button>
<button class="bbcode" title="Таблица" data-code="table">table</button>
<button class="bbcode" title="Строка таблицы" data-code="tr">tr</button>
<button class="bbcode" title="Ячейка таблицы" data-code="td">td</button>
<button class="bbcode" title="Нумерованный список" data-code="ol">ol</button>
<button class="bbcode" title="Ненумерованный список" data-code="ul">ul</button>
<button class="bbcode" title="Элемент списка" data-code="li">li</button>
`);
}
}
function setAvatar(catId, selector) {
$.get('/cat' + catId.toString(),
function (data) {
const temp = $('<div/>', { html: data });
let avatar = temp.find('[src*=avatar]').attr('src');
if (!avatar) avatar = '//e.catwar.su/avatar/0.jpg';
try {
window.sessionStorage.setItem('avatar' + catId, avatar);
} catch (err) { }
$(selector).css('background-image', `url(${avatar})`);
}
);
}
function setCatName(catId, selector, oldName) {
$.post('/preview', { text: `[link${catId}]` }, function (data) {
data = data.replace(/<\/?div( class="parsed")?>/, '');
$(selector).html(data);
if (oldName && $(selector).text() !== oldName) {
$(selector).html(data + ' (' + oldName + ')');
}
});
}
function getCatIdByName(name, callback) {
$.post('/ajax/top_cat', { name: name }, function (data) {
const catId = parseInt(data, 10);
callback(catId);
});
}
function getCurrentUser(callback) {
$.get('/',
function (data) {
const temp = $('<div/>', { html: data });
const catId = temp.find('a[href^="cat"]').first().text();
const catName = temp.find('big').first().text();
callback(catId, catName)
}
);
}
function dateToString(date) {
if (typeof date === 'number') date = new Date(date);
const dateString = date.toISOStringLocal();
return dateString.slice(0, 16);
}
function declOfNum(n, titles) {
n = Math.abs(n);
if (isNaN(n)) return titles[2];
if (!Number.isInteger(n)) return titles[1];
n %= 100;
if (n > 10 && n < 20) return titles[2];
n %= 10;
if (n === 1) return titles[0];
if (n > 1 && n < 5) return titles[1];
return titles[2];
}
function convertTime(units, val) {
const allUnits = ['ms', 's', 'm', 'h', 'd'];
units = units.split(' ');
let valUnit = allUnits.indexOf(units[0]);
const resultUnit = allUnits.indexOf(units[1]);
const multipliers = [1000, 60, 60, 24];
if (valUnit > resultUnit) while (valUnit !== resultUnit) {
val *= multipliers[valUnit - 1];
valUnit--;
}
else while (valUnit !== resultUnit) {
val /= multipliers[valUnit];
valUnit++;
}
return val;
}
function findDate(text) {
return text.match(/(\d?\d )?[а-я]+ (\d{4} )?в \d?\d:\d\d/i)[0];
}
function catTimeToMs(y, m, d, h, min, s) {
// отсчёт месяцев с 0, дней с 1
const result = (((((((y * 12 + m) * 28 + --d) * 24 + h) * 60) + min) * 60) + s) * 1000 / 7;
return Math.round(result);
}
function timestampToCatTime(timestamp) {
const secInYear = 12 * 28 * 24 * 60 * 60;
const secInMonth = 28 * 24 * 60 * 60;
const ms = timestamp - catTimeStart;
let time = Math.round(ms / 1000 * 7);
const year = Math.floor(time / secInYear);
time -= year * secInYear;
const month = Math.floor(time / secInMonth);
time -= month * secInMonth;
const day = Math.floor(convertTime('s d', time));
time -= convertTime('d s', day);
const hour = Math.floor(convertTime('s h', time));
time -= convertTime('h s', hour);
const minute = Math.floor(convertTime('s m', time));
time -= convertTime('m s', minute);
const second = time;
return {
year: year
, month: month
, day: day + 1
, hour: hour
, minute: minute
, second: second
};
}
function getNumber(s) {
return Number(s.match(/\d+/)[0]);
}
function bbencode(html) {
html = html.replace(/<br>/g, '[br]');
html = html.replace(/<(\/?)b>/gm, '[$1b]');
html = html.replace(/<(\/?)i>/gm, '[$1i]');
html = html.replace(/<(\/?)s>/gm, '[$1s]');
html = html.replace(/<(\/?)u>/gm, '[$1u]');
html = html.replace(/<\/?tbody>/gm, '');
html = html.replace(/<(\/?)table>/gm, '[$1table=0]');
html = html.replace(/<(\/?)table border="1">/gm, '[$1table]');
html = html.replace(/<(\/?)tr>/gm, '[$1tr]');
html = html.replace(/<td align="center" valign="top" style="height:25px">(.(?![/b]<\/td>)+)<\/td>/gm, '[td][center]$1[/center][/td]');
html = html.replace(/<(\/?)td>/gm, '[$1td]');
html = html.replace(/[td][i]Цитата:[/i](.(?![/td])+)[/td]/gm, '[td][size=10][i]Цитата:[/i]$1[/size][/td]');
html = html.replace(/<a href="([^"]+)"( target="_blank")?>/gm, '[url=$1]');
html = html.replace(/<\/a>/gm, '[/url]');
html = html.replace(/<img src="([^"]+)"( alt="([^"]+)")?( style="max-width: 4000px;")?>/gm, '[img]$1[/img]');
html = html.replace(/<iframe width="640" height="390" src="https:\/\/www\.youtube\.com\/embed\/([^"]+)" frameborder="0" allowfullscreen=""><\/iframe>/gm, '[header=$1]Видеозапись[/header][br][block=$1][video]$1[/video][/block]');
html = html.replace(/<audio controls=""><source src="([^"]+)" type="audio\/mpeg"> Воспроизведение аудиофайлов не поддерживается вашим браузером.<\/audio>/gm, '[header=$1]Аудиозапись[/header][br][block=$1][audio]$1[/audio][/block]');
html = html.replace(/<(\/?)li>/gm, '[$1li]');
html = html.replace(/<(\/?)ol( style="display:inline-block")?>/gm, '[$1ol]');
html = html.replace(/<(\/?)ul( style="display:inline-block")?>/gm, '[$1ul]');
html = html.replace(/<[^>]+>/gm, '');
html = decodeHTML(html);
return html;
}
})(window, document, jQuery);