Mediawiki:common.js
| Строка 106: | Строка 106: | ||
}; | }; | ||
var LawTooltipsModule = { | |||
init: function () { | |||
var tableCells = document.querySelectorAll('.law-tooltips td, .law-tooltips th'); | |||
if (tableCells.length === 0) return; | |||
MediaWikiTooltips.load(function () { | |||
var lawData = LawTooltipsModule.extractLawData(); | |||
LawTooltipsModule.initCellTooltips(tableCells, lawData); | |||
}); | |||
}, | |||
extractLawData: function () { | |||
var lawData = {}; | |||
var crimeIdSpans = document.querySelectorAll('table.wikitable span[id^="§_"]'); | |||
crimeIdSpans.forEach(function (span) { | |||
var lawCode = span.id; | |||
if (!lawCode) return; | |||
var tr = span.closest('tr'); | |||
if (!tr) return; | |||
var cells = tr.querySelectorAll('td'); | |||
if (cells.length < 3) return; | |||
var crimeCell = cells[0]; | |||
var descriptionCell = cells[1]; | |||
var exampleCell = cells[2]; | |||
var title = LawTooltipsModule.extractTitleFromCrimeCell(crimeCell); | |||
if (!title) return; | |||
var description = (descriptionCell.innerHTML || '').trim(); | |||
var examples = LawTooltipsModule.extractExamplesFromExampleCell(exampleCell); | |||
lawData[lawCode] = { | |||
title: title, | |||
description: description, | |||
examples: examples | |||
}; | |||
}); | |||
return lawData; | |||
}, | |||
extractTitleFromCrimeCell: function (crimeCell) { | |||
var b = crimeCell.querySelector('b'); | |||
var text = (b ? b.textContent : crimeCell.textContent) || ''; | |||
text = text.replace(/\s+/g, ' ').trim(); | |||
// Пример текста: "§ 1.1 Оскорбительное поведение" | |||
text = text.replace(/^§\s*[\d]+(?:\.\s*[\d]+)*\s*/,'').trim(); | |||
return text; | |||
}, | |||
extractExamplesFromExampleCell: function (exampleCell) { | |||
var examples = []; | |||
var liItems = exampleCell.querySelectorAll('li'); | |||
if (liItems.length > 0) { | |||
liItems.forEach(function (item) { | |||
var html = (item.innerHTML || '').trim(); | |||
html = html.replace(/<br\s*\/?>/gi, ''); | |||
html = html.trim(); | |||
if (html) examples.push(html); | |||
}); | }); | ||
} | return examples; | ||
} | |||
// На случай, если вместо <li> будет иной формат | |||
var fallback = (exampleCell.innerHTML || '').trim(); | |||
fallback = fallback.replace(/<br\s*\/?>/gi, '').trim(); | |||
if (fallback) examples.push(fallback); | |||
return examples; | |||
}, | |||
formatLawCode: function (lawCode) { | |||
// §_1.1 -> § 1.1 | |||
return (lawCode || '').replace(/^§_/, '§ '); | |||
}, | |||
createTooltipContent: function (lawCode, lawData) { | |||
var data = lawData[lawCode]; | |||
if (!data) return null; | |||
var displayCode = LawTooltipsModule.formatLawCode(lawCode); | |||
var html = '<div class="law-tooltip">'; | |||
html += '<h4 class="law-tooltip-title">' + displayCode + ' - ' + data.title + '</h4>'; | |||
html += '<p class="law-tooltip-description">' + (data.description || '') + '</p>'; | |||
if (data.examples && data.examples.length > 0) { | |||
html += '<div class="law-tooltip-examples">'; | |||
html += '<strong>Примеры:</strong><ul>'; | |||
data.examples.slice(0, 5).forEach(function (example) { | |||
html += '<li>' + example + '</li>'; | |||
}); | |||
html += '</ul></div>'; | |||
} | |||
html += '</div>'; | |||
return html; | |||
}, | |||
initCellTooltips: function (tableCells, lawData) { | |||
tableCells.forEach(function (cell) { | |||
if (cell.dataset.lawTooltipAttached === '1') return; | |||
var link = cell.querySelector('a[href^="#"]'); | |||
if (!link) return; | |||
var href = link.getAttribute('href') || ''; | |||
var match = href.match(/^#(.+)$/); | |||
if (!match) return; | |||
createTooltipContent: function(lawCode, lawData) { | |||
var lawCode = match[1]; | |||
if (!lawCode) return; | |||
var tooltipContent = LawTooltipsModule.createTooltipContent(lawCode, lawData); | |||
if (!tooltipContent) return; | |||
cell.dataset.lawTooltipAttached = '1'; | |||
cell.classList.add('law-cell-with-tooltip'); | |||
cell.addEventListener('click', function (e) { | |||
e.preventDefault(); | |||
window.location.hash = lawCode; | |||
}); | |||
tippy(cell, { | |||
content: tooltipContent, | |||
allowHTML: true, | |||
interactive: true, | |||
placement: 'top', | |||
maxWidth: 400, | |||
theme: 'law-theme', | |||
arrow: true, | |||
duration: [200, 150], | |||
delay: [0, 50], | |||
appendTo: document.body, | |||
boundary: 'viewport', | |||
popperOptions: { | |||
strategy: 'fixed', | |||
modifiers: [ | |||
{ | |||
name: 'preventOverflow', | |||
options: { | |||
boundary: 'viewport', | |||
padding: 20, | |||
altAxis: true, | |||
altBoundary: true | |||
} | } | ||
}, | |||
{ | |||
name: 'flip', | |||
options: { | |||
fallbackPlacements: ['bottom', 'left', 'right'] | |||
} | } | ||
}); | }, | ||
} | { | ||
} | name: 'computeStyles', | ||
options: { adaptive: false } | |||
} | |||
] | |||
}, | |||
onShow: function (instance) { | |||
document.querySelectorAll('[data-tippy-root]').forEach(function (tooltip) { | |||
if (tooltip._tippy && tooltip._tippy !== instance) { | |||
tooltip._tippy.hide(); | |||
} | |||
}); | |||
} | |||
}); | }); | ||
} | }); | ||
}; | } | ||
}; | |||
var DataTooltipsModule = { | var DataTooltipsModule = { | ||