Функції JScript і стилізація CSS коментарів для блоків коду в статтях з темною темою.
Реалізовано можливість копіювання множинних блоків коду на одній сторінці.
Стилізація коментарів залежить від типу кодового блоку і визначається CSS-класами, що додаються.
/* Основні стилі для контейнера з кодом*/
.code-container {
font-family: "Fira Code", monospace;
background-color: #2d2d2d;
color: #ccc;
padding: 10px;
border-radius: 5px;
white-space: pre-wrap;
overflow-x: auto;
}
.html-comment {
color: #6a9955;
font-style: italic;
}
.css-comment {
color: #6bbc45;
font-style: italic;
}
.js-comment {
color: #808080;
font-style: italic;
}
.hash-comment {
color: #b5cea8;
font-style: italic;
}
.brace {
color: #6bbc45;
font-weight: bold;
}
Основний скрипт розбирає текст контейнера за допомогою регулярного виразу, розділяє коментарі за типом (HTML, CSS, JS) і огортає відповідними класами CSS для їх колоризації.
function highlightComments(container) {
if (container.classList.contains('highlighted')) return;
container.classList.add('highlighted');
const code = container.textContent;
const fragment = document.createDocumentFragment();
// Регулярний вираз
const parts = code.split(
/(https?:\/\/[^\s]+|<!--[\s\S]*?-->|\/\*[\s\S]*?\*\/|\/\/.*$|(^|\s)#(?![a-fA-F0-9]{3,6}\b).*|[{}])/gm
).filter(Boolean);
parts.forEach(part => {
const span = document.createElement('span');
let matched = false;
if (/^https?:\/\/[^\s]+$/.test(part)) {
span.className = 'url';
} else if (/^<!--[\s\S]*?-->$/.test(part)) {
span.className = 'html-comment';
} else if (/^\/\*[\s\S]*?\*\/$/.test(part)) {
span.className = 'css-comment';
} else if (/^\/\/.*$/.test(part)) {
span.className = 'js-comment';
} else if (/^(\s*)#(?![a-fA-F0-9]{3,6}\b).*$/.test(part)) {
// # коментар тільки якщо не перед кольором
span.className = 'hash-comment';
} else if (/^[{}]$/.test(part)) {
span.className = 'brace';
} else {
span.textContent = part;
fragment.appendChild(span);
return;
}
span.textContent = part;
fragment.appendChild(span);
});
container.innerHTML = '';
container.appendChild(fragment);
}
// Ініціалізація підсвічування для всіх контейнерів з класом .code-container
function setupHighlighting() {
document.querySelectorAll('.code-container').forEach(container => {
highlightComments(container);
});
}
// Виклик підсвічування під час завантаження сторінки
window.addEventListener('load', setupHighlighting);
Для додавання властивостей підсвічування коментарів, слід лише прописати клас code-container у відповідних тегах. Варто нагадати ще раз: властивість розповсюджується на текст лише у межах наступного блоку, до якого прописаний клас.
<pre class="code-container">
<!-- HTML .html-comment -->
/* CSS .css-comment */
// JS .js-comment
# Hash .hash-comment
$100 {...}
</pre>
Пропонуються дві функції, які виконують одну й ту ж дію - копіювання в буфер обміну, але по-різному виконують це на сторінці в браузері. Перший спосіб є традиійним, з використанням кнопки копіювання тексту, а другий здійснює копіювання після кліку на відповідному блоці без відображення додаткових елементів.
У функції copyToClipboard використовується button.nextElementSibling
для пошуку наступного елемента, який відповідає блоку тексту. Така прив'язка, яка не задіює id для ідентифікації елемента та виконується автоматично.
// Копіювання тексту в буфер обміну через кнопку
function copyToClipboard(button) {
const container = button.nextElementSibling; // Знаходження наступного блоку коду
const code = container.textContent;
// Створення виділення для копіювання
const range = document.createRange();
range.selectNodeContents(container);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
navigator.clipboard.writeText(code) // Копіювання тексту
.then(() => {
alert('Код успішно скопійовано в буфер обміну!');
setTimeout(() => selection.removeAllRanges(), 500); // Скинути виділення
})
.catch(err => console.error('Помилка копіювання:', err));
}
Для додавання в HTML, слід прописати клас class="copy-button" та локатор події onclick="copyToClipboard(this)" у тегах самої кнопки. Не слід забувати, що: властивість розповсюджується на текст лише у межах наступного блоку, до якого відноситься кнопка.
<!-- Демо копіювання в HTML --> <button class="copy-button" onclick="copyToClipboard(this)">Копіювати</button> <pre>.. тут текст .. </pre>
У функції copyCode використовується element.parentElement
для пошуку наступного елемента, який відповідає блоку тексту. Така прив'язка, яка не задіює id для ідентифікації елемента та виконується автоматично.
// Копіювання тексту в буфер обміну через виділення
function copyCode(element) {
const codeContainer = element.parentElement; // Знайти батьківський тег
const code = codeContainer.textContent.trim();
// Виділення тексту
const range = document.createRange();
range.selectNodeContents(codeContainer);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
// Копіювання тексту
navigator.clipboard.writeText(code)
.then(() => {
alert('Код успішно скопійовано в буфер обміну!');
setTimeout(() => selection.removeAllRanges(), 500); // Скинути виділення
})
.catch(err => console.error('Помилка копіювання:', err));
}
Для додавання в HTML, слід прописати клас class="code-container" та локатор події onclick="copyCode(this)" у відповідних тегах. Не слід забувати, що: властивість розповсюджується на текст лише у межах наступного блоку, до якого відноситься кнопка.
<!-- Демо копіювання в HTML --> <pre class="code-container" style="cursor: pointer" title="Натисніть, щоб скопіювати" onclick="copyCode(this)"> .. тут текст .. </pre>
Тепер, навівшись на блок з текстом, і зробивши на ньому лівий клік, отримаємо його вміст буфері обміну. Додатково, можна візалізувати дію додавши вказівник style="cursor: pointer" та спливаючу тайтл-підказку.
Задля економії місця на сторінці - простий варіант незалежних блоків тексту, з використанням nextElementSibling для пошуку наступного.
// Функція згортання/розгортання блоку
function togglePre(button) {
const wrapper = button.nextElementSibling; // Відповідний контейнер
const isHidden = wrapper.style.display === 'none';
wrapper.style.display = isHidden ? 'block' : 'none'; // Перемикання видимості
button.textContent = isHidden ? 'Сховати демо' : 'Показати демо';
}
// Додавання обробників подій для кнопок згортання/розгортання
window.addEventListener('load', function () {
document.querySelectorAll('.toggle-button').forEach(button => {
button.addEventListener('click', () => togglePre(button));
});
});