whatsapp
Создание сайтов на 1С-Битрикс

Подсветка синтаксиса и копирование в буфер обмена на чистом js

Как мы сделали на этом сайте - какие инструменты и скрипты использовали

Подсветка синтаксиса и копирование в буфер обмена на чистом js Как мы сделали на этом сайте - какие инструменты и скрипты использовали

Подсветка синтаксиса

Пробуя разные методы — в PHP, мини-js-скрипты и т.д., мы остановились на Highlight.js.
Подкупил маленький размер, возможность выбрать только нужные нам синтаксисы (PHP, html, CSS), множество цветовых тем для самых придирчивых программистов ))

Наш CSS для этих блоков:

pre {
font-size: 1rem;
font-family: ui-monospace,"Cascadia Mono","Segoe UI Mono","Liberation Mono",Menlo,Monaco,Consolas,monospace;
line-height: 1.30769231;
color: #2f3337;
background-color: #fafafa;
margin: 0;
overflow: auto;
-webkit-overflow-scrolling: touch;
width: auto;
max-height: 50vh;
scrollbar-color: rgba(0,0,0,0.2) transparent;
border: 1px solid #e5e8ec;
border-radius: 5px;
position: relative;
}

pre code {
padding: 1rem;
}

@media screen and (max-width: 767px) {
  pre {
  max-width: calc(100vw - 40px);
  }
  code {
  white-space: pre-wrap;
  }
}

И цветовая тема:

.hljs {
display: block;
color: #383a42;
}

.hljs-comment, .hljs-quote {
color: #a0a1a7;
font-style:italic
}

.hljs-doctag, .hljs-keyword, .hljs-formula {
color:#a626a4
}

.hljs-section, .hljs-name, .hljs-selector-tag, .hljs-deletion, .hljs-subst {
color:#e45649
}

.hljs-literal {
color:#0184bb
}

.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute, .hljs-meta-string {
color:#50a14f
}

.hljs-built_in, .hljs-class .hljs-title {
color:#c18401
}

.hljs-attr, .hljs-variable, .hljs-template-variable, .hljs-type, .hljs-selector-class, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-number {
color:#986801
}

.hljs-symbol, .hljs-bullet, .hljs-link, .hljs-meta, .hljs-selector-id, .hljs-title {
color:#4078f2
}

.hljs-emphasis {
font-style:italic
}

.hljs-strong {
font-weight:700
}

.hljs-link {
text-decoration:underline
}

Все что вам нужно — это скачать Custom package (выбрать нужные языки для подсветки), подключить на своем сайте highlight.min.js и добавить CSS по вкусу.

И конечно инициализировать скриптом JS:

document.addEventListener("DOMContentLoaded", function(event) { 
    document.querySelectorAll('pre code').forEach((el) => {
        hljs.highlightElement(el); // Подсветка кода
      });
});

Добавление кнопки Копировать

Этот скрипт мы взяли отсюда и переделали "под себя". Чистый JS, без использования Jquery:

document.addEventListener("DOMContentLoaded", function(event) { 

setAutoCopyFeatures();; // Инициализация скрипта для копирования кода

function setAutoCopyFeatures() {

    function create(htmlStr) { // Вспомогательная функция для создания DOM-элемента
        var frag = document.createDocumentFragment(),
            temp = document.createElement('div');
        temp.innerHTML = htmlStr;
        while (temp.firstChild) {
            frag.appendChild(temp.firstChild);
        }
        return frag;
    }

    function insertButtonCopy() {
    let precode = document.querySelectorAll('pre code');

    for( let i = 0; i < precode.length; i++ ) { // Добавление кнопки к каждому блоку pre code
        var fragment = create('<div class="js-copy-btn"><svg class="icon-copy" role="img" aria-label="Скопировать в буфер обмена"><title>Копировать</title><use xlink:href="#copy"></use></svg></div>');
        let parentDiv = precode[i].parentNode;
        parentDiv.insertBefore(fragment, precode[i]);

        parentDiv.addEventListener('scroll', function() { // Чтобы при скролле иконка оставалась на месте
            var btnCopy = parentDiv.querySelector('.js-copy-btn');
            var btnWidth = btnCopy.getBoundingClientRect().width;

            if(parentDiv.scrollTop > 0) { // При вертикальной прокрутке
                btnCopy.style.top = parentDiv.scrollTop+"px";
            } else {
                btnCopy.style.top = '';
            }
            if(parentDiv.scrollLeft > 0) { // При горизонтальной прокрутке
                let offsetBtnLeft = parentDiv.clientWidth + parentDiv.scrollLeft - btnWidth;
                btnCopy.style.right = 'unset';
                btnCopy.style.left = offsetBtnLeft + "px";
            } else {
                btnCopy.style.right = '0';
                btnCopy.style.left = '';
            }
        }, false);

        }
    }
    insertButtonCopy();
    onclick_copyFrom();

    function onclick_copyFrom() {
    let btn = document.querySelectorAll('.js-copy-btn');

    for( let i = 0; i < btn.length; i++ ) {
      btn[i].addEventListener('click', function() {
        let parentDiv = this.parentNode;
        let childCheck = parentDiv.querySelector('.js-copy-done');
        if(childCheck) return; // Если еще существует .js-copy-done, то прерываем (проверка на двойное нажатие)

        let copyCode = this.nextSibling;
        
        copyToClipboard(copyCode.textContent);
        ui_copyDone(this);
      });
    }
    }

    function copyToClipboard(str) {
        var area = document.createElement('textarea');

        document.body.appendChild(area);
        let replaced = str.replaceAll("\u00A0", " "); // Удаляем неразрывные пробелы
        area.value = replaced;
        area.select();
        document.execCommand("copy");
        document.body.removeChild(area);
    }

    function ui_copyDone(btn) {
        var doneElement = create('<div class="js-copy-done">Скопировано</div>');
        let parentDiv = btn.parentNode;
        parentDiv.insertBefore(doneElement, btn);
        var insertedElement = parentDiv.querySelector('.js-copy-done');

        if(parentDiv.scrollTop > 0) { // Если была прокрутка, то сдвигаем к центру (горизонталь)
            insertedElement.style.top = parentDiv.scrollTop+(parentDiv.getBoundingClientRect().height/2)+"px";
        }
        if(parentDiv.scrollLeft > 0) { // Если была прокрутка, то сдвигаем к центру (вертикаль)
            insertedElement.style.left = parentDiv.scrollLeft+(parentDiv.clientWidth/2)+"px";
        }

        setTimeout(function() { // Пауза перед исчезновением
            var child = parentDiv.querySelector('.js-copy-done');
            child.classList.add('faded');
            removeCopyDone(child);
        }, 500);

        function removeCopyDone(child) {
            setTimeout(function() {
                parentDiv.removeChild(child);
            }, 500);
        }
    }
}

});

CSS:

/**** JS copy Code ***/

.js-copy-btn {
opacity: 0;
transition: opacity 0.2s;
position: absolute;
right: 0;
top: 0;
padding: 0.75rem;
}

.js-copy-btn .icon-copy {
width: 1rem;
height: 1rem;
display: block;
}

pre:hover .js-copy-btn {
  opacity: 0.2;
}

pre .js-copy-btn:hover {
  opacity: 0.4;
  cursor: pointer;
  cursor: hand;
}

.js-copy-done {
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
top: 50%;
background-color: rgba(0, 0, 0, 0.6);
color: white;
padding: .75rem 1.5rem;
border-radius: 3px;
transition: opacity 0.5s;
}

.js-copy-done.faded {
opacity: 0;
}

И как вы заметили, кнопка представляет собой SVG symbol. Для этого нужно добавить в html страницы (желательно в начало, после тега BODY следующий код:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="display: none;">
    <symbol id="copy" x="0" y="0" viewBox="0 0 17.2 17.2">
      <style>
        .st0{fill:none;stroke:#000;stroke-width:1.3251;stroke-miterlimit:10}
      </style>
      <path class="st0" d="M12.6 12.6h2.8c.7 0 1.2-.5 1.2-1.2V1.9c0-.7-.5-1.2-1.2-1.2H5.8c-.7 0-1.2.5-1.2 1.2v2.8"/>
      <path class="st0" d="M11.4 4.7H1.9c-.7 0-1.2.5-1.2 1.2v9.5c0 .7.5 1.2 1.2 1.2h9.5c.7 0 1.2-.5 1.2-1.2V5.8c0-.6-.5-1.1-1.2-1.1z"/>
    </symbol>
</svg>

Если вам нужна другая кнопка, то замените строчку js-кода "Добавление кнопки к каждому блоку pre code" на этот:

var fragment = create('<div class="js-copy-btn">Копировать</div>'); // Строка с кнопкой для копирования

Мы запаковали все вместе в архив и добавили инструкцию в файл readme.php.
Скачивайте архив и устанавливайте на свой сайт 😄

Скачать архив: highlight-copy.zip

Логотип SiteBERG
Изменено: 11.06.2021 18:53