Теги: Test
- Подпись автора
Подпись - это небольшая приписка, прилагаемая к вашим сообщениям. Это может быть все, что вам нравится. Например
1
96
Mistake Not |
Привет, Гость! Войдите или зарегистрируйтесь.
Вы здесь » Mistake Not » Falling Outside the Normal Moral Constraints » script
Теги: Test
Подпись - это небольшая приписка, прилагаемая к вашим сообщениям. Это может быть все, что вам нравится. Например
1
96
<!-- SPRING by @vatueil -->
<script>
/*
* christmas ornaments
* version: v1.1.0
* copyright (c) 2026 @vatueil for executecross.ru
* need <div id="springOrnaments"></div> in html bottom
*/
class UniqueSelector {
static getElementSelector(element) {
if (element._uniqueSelectorCache) {
return element._uniqueSelectorCache;
}
if (element.id) {
const selector = `#${CSS.escape(element.id)}`;
element._uniqueSelectorCache = selector;
return selector;
}
if (element.tagName === 'BODY') {
element._uniqueSelectorCache = 'body';
return 'body';
}
let selector = element.tagName.toLowerCase();
if (element.className && typeof element.className === 'string') {
const className = element.className.trim();
if (className) {
const classList = className.split(/\s+/).filter(cls =>
cls && cls !== 'highlight' && cls !== 'decoratable' && cls !== 'ornaments-container'
);
if (classList.length > 0) {
selector += '.' + classList.map(c => CSS.escape(c)).join('.');
}
}
}
const parent = element.parentNode;
if (parent && parent.children && parent.children.length > 1) {
let index = 1;
for (let i = 0; i < parent.children.length; i++) {
if (parent.children[i] === element) {
selector += `:nth-child(${index})`;
break;
}
index++;
}
}
element._uniqueSelectorCache = selector;
return selector;
}
static getUniqueSelector(element) {
let selector = this.getElementSelector(element);
let elements;
try {
elements = document.querySelectorAll(selector);
} catch (e) {
return selector;
}
if (elements.length === 1) {
return selector;
}
let bestSelector = selector;
let bestCount = elements.length;
const queryCache = new Map();
const queryElements = (sel) => {
if (queryCache.has(sel)) {
return queryCache.get(sel);
}
try {
const result = document.querySelectorAll(sel);
queryCache.set(sel, result);
return result;
} catch {
return [];
}
};
let parent = element.parentElement;
while (parent) {
if (parent.id) {
const parentSelector = `#${CSS.escape(parent.id)} ${selector}`;
elements = queryElements(parentSelector);
if (elements.length === 1) {
UniqueSelector.clearCache(parent);
return parentSelector;
}
if (elements.length < bestCount) {
bestSelector = parentSelector;
bestCount = elements.length;
}
}
parent = parent.parentElement;
}
const usedParentClasses = new Set();
parent = element.parentElement;
while (parent && parent.tagName !== 'BODY') {
const classList = Array.from(parent.classList).filter(c =>
!usedParentClasses.has(c) &&
c !== 'highlight' &&
c !== 'decoratable' &&
c !== 'ornaments-container'
);
for (const cls of classList) {
const parentSelector = `.${CSS.escape(cls)} ${selector}`;
elements = queryElements(parentSelector);
if (elements.length === 1) {
UniqueSelector.clearCache(parent);
return parentSelector;
}
if (elements.length < bestCount) {
bestSelector = parentSelector;
bestCount = elements.length;
}
usedParentClasses.add(cls);
}
parent = parent.parentElement;
}
parent = element.parentElement;
let selectors = [selector];
while (parent && parent.tagName !== 'BODY') {
const parentSelector = this.getElementSelector(parent);
const newSelectors = [];
for (const sel of selectors) {
const newSelector = `${parentSelector} ${sel}`;
newSelectors.push(newSelector);
elements = queryElements(newSelector);
if (elements.length === 1) {
UniqueSelector.clearCache(parent);
return newSelector;
}
if (elements.length < bestCount) {
bestSelector = newSelector;
bestCount = elements.length;
}
}
selectors = newSelectors;
parent = parent.parentElement;
}
return bestSelector;
}
static clearCache(element) {
delete element._uniqueSelectorCache;
}
}
class ForumDecorator {
constructor(config) {
this.config = {
decoratableSelectors: ['.pa-author, .pa-posts, .pa-fld3, .pa-fld2', '#profile-name, #pa-fld3 strong, #pa-fld2 strong, #pa-posts a', '#pun-navlinks li:not(#navlogout)', '.crumbs a', '.pa-fld1 .lz-name', '#post-form h2 span', '.permalink, .postlink a', '.tclcon h3 a, .tcl h3 a, .pf > a, .lastpost-link, .avatar-image', '.button', '#pun-status .container', ".statscon span", "h1 span", ".announce-btn, #pun-announcement .character-wrapper"],
maxOrnaments: 2025,
ornamentCategories: [
{
name: 'Цветы',
images: [
"https://forumstatic.ru/files/001b/f1/8a/42536.webp?v=1",
"https://forumstatic.ru/files/001b/f1/8a/32614.webp?v=1",
"https://forumstatic.ru/files/001b/f1/8a/63068.png?v=1",
"https://forumstatic.ru/files/001b/f1/8a/39327.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/45666.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/14658.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/96576.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/66356.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/88283.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/36804.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/56082.webp?v=1",
]
},
{
name: 'Зелень',
images: [
"https://forumstatic.ru/files/001b/f1/8a/30630.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/25010.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/66763.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/54117.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/46868.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/14096.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/67503.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/92313.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/34272.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/72885.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/55623.webp?v=1"
]
},
{
name: 'Бабочки',
images: [
"https://forumstatic.ru/files/001c/7f/71/86329.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/76207.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/63953.webp?v=1",
"https://forumstatic.ru/files/001b/f1/8a/15694.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/28830.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/89872.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/22835.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/68567.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/91548.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/53938.webp?v=1",
"https://forumstatic.ru/files/001c/7f/71/79345.webp?v=1",
]
}
],
storageKey: 'forum_decor_spring',
...config
};
this.ornaments = [];
this.draggingFromCollection = null;
this.isPanelCollapsed = this.loadPanelState();
this.currentTab = 0;
this.decoratableElements = null;
this.decoratableCacheTime = 0;
this.cacheTTL = 1000;
this.save = this.debounce(this.save.bind(this), 500);
this.preloadedImages = new Set();
this.init();
}
init() {
this.createContainer();
this.markDecoratableElements();
this.createCollectionPanel();
this.preloadImages();
this.loadSavedDecorations();
this.setupGlobalEvents();
}
createContainer() {
this.container = document.getElementById('springOrnaments') ||
document.body.appendChild(document.createElement('div'));
this.container.id = 'springOrnaments';
}
markDecoratableElements() {
const fragment = document.createDocumentFragment();
this.config.decoratableSelectors.forEach(selector => {
try {
const elements = document.querySelectorAll(selector);
elements.forEach(el => {
el.classList.add('decoratable');
if (!el.querySelector('.ornaments-container')) {
const container = document.createElement('div');
container.className = 'ornaments-container spring';
el.appendChild(container);
}
});
} catch (e) {
console.warn('Неверный селектор:', selector, e);
}
});
}
getDecoratableElements() {
const now = Date.now();
if (!this.decoratableElements || (now - this.decoratableCacheTime) > this.cacheTTL) {
this.decoratableElements = [];
this.config.decoratableSelectors.forEach(selector => {
try {
const elements = document.querySelectorAll(selector);
this.decoratableElements.push(...elements);
} catch (e) {
console.warn('Ошибка в селекторе:', selector);
}
});
this.decoratableCacheTime = now;
}
return this.decoratableElements;
}
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
preloadImages() {
const allImages = this.getAllImages();
allImages.forEach(src => {
if (!this.preloadedImages.has(src)) {
const img = new Image();
img.src = src;
this.preloadedImages.add(src);
}
});
}
createCollectionPanel() {
this.panel = document.createElement('div');
this.panel.className = `ornament-collection ${this.isPanelCollapsed ? 'collapsed' : ''}`;
const tabsHTML = this.config.ornamentCategories.map((cat, index) =>
`<div class="collection-tab ${index === 0 ? 'active' : ''}" data-tab="${index}">${cat.name}</div>`
).join('');
this.panel.innerHTML = `
<div class="collection-toggle">
<i class="fi fi-ss-flower-tulip"></i>
</div>
<div class="collection-tabs">${tabsHTML}</div>
${this.config.ornamentCategories.map((_, index) =>
`<div class="collection-items ${index === 0 ? '' : 'hidden'}" data-tab-content="${index}"></div>`
).join('')}
<div class="collection-footer">
<p><strong>Shift + Click</strong> чтобы убрать украшение</p>
<button class="button btn-sm" onclick="window.decor.resetAll()">
Сбросить все
</button>
</div>
`;
document.body.appendChild(this.panel);
this.panel.addEventListener('click', (e) => {
const tab = e.target.closest('.collection-tab');
if (tab) {
const tabIndex = parseInt(tab.dataset.tab);
this.switchTab(tabIndex);
}
});
requestAnimationFrame(() => {
this.updatePanel();
});
this.panel.querySelector('.collection-toggle').addEventListener('click', () => {
this.panel.classList.toggle('collapsed');
this.isPanelCollapsed = this.panel.classList.contains('collapsed');
this.savePanelState();
});
}
loadPanelState() {
return localStorage.getItem(`${this.config.storageKey}_panelState`) === 'false' || localStorage.getItem(`${this.config.storageKey}_panelState`) === null ? false : true;
}
savePanelState() {
try {
localStorage.setItem(
`${this.config.storageKey}_panelState`,
JSON.stringify(this.isPanelCollapsed)
);
} catch (e) {
console.warn('Не удалось сохранить состояние панели:', e);
}
}
switchTab(tabIndex) {
if (this.currentTab === tabIndex) return;
this.currentTab = tabIndex;
this.panel.querySelectorAll('.collection-tab').forEach(tab => {
tab.classList.toggle('active', parseInt(tab.dataset.tab) === tabIndex);
});
this.panel.querySelectorAll('.collection-items').forEach(content => {
content.classList.toggle('hidden', parseInt(content.dataset.tabContent) !== tabIndex);
});
requestAnimationFrame(() => {
this.updateCurrentTab();
});
}
updatePanel() {
requestAnimationFrame(() => {
this.updateCurrentTab();
});
}
updateCurrentTab() {
const currentCategory = this.config.ornamentCategories[this.currentTab];
const itemsContainer = this.panel.querySelector(`.collection-items[data-tab-content="${this.currentTab}"]`);
if (!itemsContainer) return;
const fragment = document.createDocumentFragment();
currentCategory.images.forEach((src, i) => {
const globalIndex = this.getGlobalIndex(this.currentTab, i);
const count = this.ornaments.filter(o => o.typeIndex === globalIndex).length;
const isAvailable = count < 3;
const btn = document.createElement('div');
btn.className = 'collection-ornament spring';
btn.dataset.category = this.currentTab;
btn.dataset.index = i;
btn.draggable = isAvailable;
if (!isAvailable) {
btn.style.opacity = '0.4';
btn.style.cursor = 'not-allowed';
} else {
btn.addEventListener('dragstart', (e) => this.startDragFromCollection(e, src, globalIndex));
btn.addEventListener('dragend', () => this.endDragFromCollection());
}
this.createOrnamentElement(btn, src);
fragment.appendChild(btn);
});
itemsContainer.innerHTML = '';
itemsContainer.appendChild(fragment);
}
getGlobalIndex(categoryIndex, itemIndex) {
let globalIndex = 0;
for (let i = 0; i < categoryIndex; i++) {
globalIndex += this.config.ornamentCategories[i].images.length;
}
return globalIndex + itemIndex;
}
getCategoryInfo(globalIndex) {
let accumulated = 0;
for (let i = 0; i < this.config.ornamentCategories.length; i++) {
const category = this.config.ornamentCategories[i];
if (globalIndex < accumulated + category.images.length) {
return {
categoryIndex: i,
categoryName: category.name,
image: category.images[globalIndex - accumulated],
localIndex: globalIndex - accumulated
};
}
accumulated += category.images.length;
}
return null;
}
getAllImages() {
return this.config.ornamentCategories.reduce((all, cat) =>
all.concat(cat.images), []);
}
createOrnamentElement(container, src) {
const img = document.createElement('img');
img.src = src;
img.loading = 'lazy';
img.style.width = '100%';
img.style.height = '100%';
img.style.objectFit = 'contain';
img.draggable = false;
container.appendChild(img);
return img;
}
startDragFromCollection(e, src, typeIndex) {
if (this.ornaments.length >= this.config.maxOrnaments) {
$.jGrowl('<i class="fi fi-ss-flower-daffodil"></i> Лимит украшений достигнут');
e.preventDefault();
return;
}
this.draggingFromCollection = { src, typeIndex };
e.dataTransfer.setData('text/plain', 'from_collection');
e.dataTransfer.effectAllowed = 'copy';
if (!this.dragGhost) {
this.dragGhost = document.createElement('div');
this.dragGhost.className = 'forum-ornament spring';
this.dragGhost.style.position = 'fixed';
this.dragGhost.style.left = '-100px';
this.dragGhost.style.pointerEvents = 'none';
this.dragGhost.style.zIndex = '99';
document.body.appendChild(this.dragGhost);
}
this.dragGhost.innerHTML = '';
this.createOrnamentElement(this.dragGhost, src);
e.dataTransfer.setDragImage(this.dragGhost, 20, 20);
const elements = this.getDecoratableElements();
for (const el of elements) {
el.classList.add('highlight');
}
}
endDragFromCollection() {
this.draggingFromCollection = null;
const elements = this.getDecoratableElements();
for (const el of elements) {
el.classList.remove('highlight');
}
}
createOrnament(src, typeIndex, x, y) {
if (this.ornaments.length >= this.config.maxOrnaments) {
$.jGrowl('<i class="fi fi-ss-flower-daffodil"></i> Лимит украшений!');
return null;
}
const id = `o_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
const o = document.createElement('div');
o.className = 'forum-ornament spring';
o.dataset.id = id;
o.dataset.typeIndex = typeIndex;
this.createOrnamentElement(o, src);
o.style.left = `${x}px`;
o.style.top = `${y}px`;
o.draggable = true;
o.addEventListener('dragstart', (e) => this.dragStart(e, o));
o.addEventListener('dragend', (e) => this.dragEnd(e, o));
this.container.appendChild(o);
const data = {
element: o,
typeIndex,
attachedTo: null,
pos: null,
selector: null,
id
};
this.ornaments.push(data);
requestAnimationFrame(() => {
this.updatePanel();
});
return data;
}
handleDrop(e) {
e.preventDefault();
e.stopPropagation();
if (!this.draggingFromCollection) return;
const { src, typeIndex } = this.draggingFromCollection;
const target = document.elementFromPoint(e.clientX, e.clientY);
const decorEl = this.findDecoratable(target, e.clientX, e.clientY);
if (decorEl) {
decorEl.classList.remove('highlight');
const selector = UniqueSelector.getUniqueSelector(decorEl);
if (!selector || selector === '') {
$.jGrowl('Ошибка сохранения позиции');
this.endDragFromCollection();
return;
}
try {
const elements = document.querySelectorAll(selector);
if (elements.length === 0 || (elements.length > 1 && !Array.from(elements).includes(decorEl))) {
$.jGrowl('Ошибка уникальности селектора');
this.endDragFromCollection();
return;
}
this.attachNewOrnament(src, typeIndex, decorEl, selector, e.clientX, e.clientY);
} catch(err) {
$.jGrowl('Неизвестная ошибка');
this.endDragFromCollection();
return;
}
} else {
const x = Math.max(10, Math.min(e.clientX - 20, window.innerWidth - 50));
const y = Math.max(10, Math.min(e.clientY - 20, window.innerHeight - 50));
this.createOrnament(src, typeIndex, x, y);
$.jGrowl(`<i class="fi fi-ss-flower"></i> Украшение добавлено`);
}
this.endDragFromCollection();
}
attachNewOrnament(src, typeIndex, el, selector, x, y) {
const data = this.createOrnament(src, typeIndex, -100, -100);
if (!data) return;
this.attachOrnament(data.element, el, selector, x, y);
}
findDecoratable(el, clientX, clientY) {
const decoratable = el.closest('.decoratable');
if (!decoratable) return null;
const rect = decoratable.getBoundingClientRect();
const ballCenterX = clientX;
const ballCenterY = clientY;
const isBelow = ballCenterY >= rect.top - 37 && ballCenterY <= rect.bottom + 20;
const isHorizontallyAligned = ballCenterX >= rect.left && ballCenterX <= rect.right;
return isBelow && isHorizontallyAligned ? decoratable : null;
}
dragStart(e, o) {
o.classList.add('dragging');
e.dataTransfer.setData('text', o.dataset.id);
const elements = this.getDecoratableElements();
for (const el of elements) {
el.classList.add('highlight');
}
}
dragEnd(e, o) {
o.classList.remove('dragging');
const elements = this.getDecoratableElements();
for (const el of elements) {
el.classList.remove('highlight');
}
const target = document.elementFromPoint(e.clientX, e.clientY);
const decorEl = this.findDecoratable(target, e.clientX, e.clientY);
if (decorEl) {
const selector = UniqueSelector.getUniqueSelector(decorEl);
if (selector && selector !== '') {
this.attachOrnament(o, decorEl, selector, e.clientX, e.clientY);
} else {
this.freeOrnament(o, e.clientX, e.clientY);
}
} else {
this.freeOrnament(o, e.clientX, e.clientY);
}
}
freeOrnament(o, clientX, clientY) {
o.style.left = `${Math.max(10, Math.min(clientX - 20, window.innerWidth - 50))}px`;
o.style.top = `${Math.max(10, Math.min(clientY - 20, window.innerHeight - 50))}px`;
o.classList.remove('attached');
if (o.parentElement !== this.container) {
this.container.appendChild(o);
}
const data = this.ornaments.find(d => d.element === o);
if (data) {
data.attachedTo = null;
data.selector = null;
data.pos = null;
this.save();
}
}
attachOrnament(o, el, selector, clientX, clientY) {
let container = el.querySelector('.ornaments-container');
if (!container) {
container = document.createElement('div');
container.className = 'ornaments-container spring';
el.appendChild(container);
}
if (o.parentElement) {
o.parentElement.removeChild(o);
}
const rect = el.getBoundingClientRect();
const relativeX = Math.max(0, Math.min(clientX - rect.left - 20, rect.width - 40));
const fixedTop = '0';
const fixedBottom = 'calc(100% - 0.15em - 24px)';
o.style.position = 'absolute';
o.style.left = `${relativeX}px`;
o.style.top = fixedTop;
o.style.transformOrigin = 'bottom center';
o.classList.add('attached');
container.appendChild(o);
const data = this.ornaments.find(d => d.element === o);
if (data) {
data.attachedTo = selector;
data.selector = selector;
data.pos = {
top: fixedTop,
left: relativeX,
width: rect.width,
page: window.location.pathname + window.location.search
};
}
this.save();
$.jGrowl('<i class="fi fi-ss-flower"></i> Украсили!');
}
resolveElementSelector(selector) {
if (!selector || selector === '') return null;
try {
const elements = document.querySelectorAll(selector);
if (elements.length === 0) {
const parts = selector.split(' ');
for (let i = 1; i < parts.length; i++) {
const partial = parts.slice(-i).join(' ');
const partialElements = document.querySelectorAll(partial);
if (partialElements.length === 1) return partialElements[0];
}
return null;
}
return elements[0];
} catch (e) {
console.warn('Ошибка разрешения селектора:', selector, e);
return null;
}
}
removeOrnament(o) {
const index = this.ornaments.findIndex(d => d.element === o);
if (index > -1) {
this.ornaments.splice(index, 1);
o.remove();
requestAnimationFrame(() => {
this.updatePanel();
this.save();
});
}
}
loadSavedDecorations() {
try {
const currentPage = window.location.pathname + window.location.search;
const savedData = localStorage.getItem(`${this.config.storageKey}_${currentPage}`);
if (!savedData) return;
const data = JSON.parse(savedData);
if (!data.ornaments || !Array.isArray(data.ornaments)) return;
const allImages = this.getAllImages();
const validOrnaments = [];
const fragment = document.createDocumentFragment();
const freeOrnaments = [];
data.ornaments.forEach(item => {
if (item.typeIndex === undefined || !allImages[item.typeIndex]) {
return;
}
const src = allImages[item.typeIndex];
const o = document.createElement('div');
o.className = 'forum-ornament spring';
this.createOrnamentElement(o, src);
o.draggable = true;
o.addEventListener('dragstart', (e) => this.dragStart(e, o));
o.addEventListener('dragend', (e) => this.dragEnd(e, o));
const ornamentData = {
element: o,
typeIndex: item.typeIndex,
attachedTo: item.attachedTo,
selector: item.selector || item.attachedTo,
pos: item.pos
};
validOrnaments.push(ornamentData);
if (item.attachedTo) {
const targetEl = this.resolveElementSelector(item.attachedTo);
if (targetEl) {
let container = targetEl.querySelector('.ornaments-container');
if (!container) {
container = document.createElement('div');
container.className = 'ornaments-container spring';
targetEl.appendChild(container);
}
container.appendChild(o);
o.style.position = 'absolute';
o.style.left = `${item.pos?.left || 0}px`;
o.style.top = item.pos?.top || '0';
o.classList.add('attached');
} else {
freeOrnaments.push({ o, item });
}
} else {
freeOrnaments.push({ o, item });
}
});
freeOrnaments.forEach(({ o, item }) => {
if (item.pos && item.pos.x && item.pos.y) {
o.style.left = `${item.pos.x}px`;
o.style.top = `${item.pos.y}px`;
} else {
o.style.left = `${50 + Math.random() * (window.innerWidth - 150)}px`;
o.style.top = `${50 + Math.random() * (window.innerHeight - 150)}px`;
}
fragment.appendChild(o);
});
this.container.appendChild(fragment);
this.ornaments = validOrnaments;
requestAnimationFrame(() => {
this.updatePanel();
});
console.log('Загружено украшений:', this.ornaments.length);
} catch(e) {
console.warn('Ошибка загрузки украшений:', e);
}
}
save() {
try {
const currentPage = window.location.pathname + window.location.search;
const validOrnaments = this.ornaments.filter(o => {
if (o.attachedTo) {
try {
return document.querySelector(o.attachedTo) !== null;
} catch {
return false;
}
}
return true;
});
const pageData = {
ornaments: validOrnaments.map(o => ({
typeIndex: o.typeIndex,
attachedTo: o.attachedTo,
selector: o.selector,
pos: o.pos
})),
timestamp: Date.now(),
version: '1.0'
};
const currentData = JSON.stringify(pageData);
const savedData = localStorage.getItem(`${this.config.storageKey}_${currentPage}`);
if (savedData !== currentData) {
localStorage.setItem(`${this.config.storageKey}_${currentPage}`, currentData);
}
} catch(e) {
console.warn('Ошибка сохранения:', e);
}
}
setupGlobalEvents() {
document.addEventListener('dragover', (e) => {
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
}, { passive: false });
document.addEventListener('drop', (e) => this.handleDrop(e), { passive: false });
document.addEventListener('click', (e) => {
if (e.shiftKey && e.target.closest('.forum-ornament')) {
const ornament = e.target.closest('.forum-ornament');
this.removeOrnament(ornament);
$.jGrowl('<i class="fi fi-ss-trash-xmark"></i> Украшение удалено');
e.stopPropagation();
}
});
const observer = new MutationObserver(() => {
this.decoratableElements = null;
this.decoratableCacheTime = 0;
});
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['class', 'id']
});
}
resetAll() {
if (confirm('Убрать все украшения?')) {
this.ornaments.forEach(o => o.element.remove());
this.ornaments = [];
const currentPage = window.location.pathname + window.location.search;
localStorage.removeItem(`${this.config.storageKey}_${currentPage}`);
requestAnimationFrame(() => {
this.updatePanel();
$.jGrowl('<i class="fi fi-ss-flower"></i> Все украшения убраны');
});
}
}
destroy() {
if (this.dragGhost) {
this.dragGhost.remove();
}
}
}
if (window.matchMedia("(min-device-width: 768px)").matches) {
document.addEventListener('DOMContentLoaded', () => {
window.decor = new ForumDecorator();
});
}
</script>
<!-- SPRING end -->Подпись - это небольшая приписка, прилагаемая к вашим сообщениям. Это может быть все, что вам нравится. Например
1
96
Вы здесь » Mistake Not » Falling Outside the Normal Moral Constraints » script