Membuat Area Teks yang Dapat Diedit Yang Mendukung Kode yang Disorot Sintaks

Ketika saya mengerjakan sebuah proyek yang membutuhkan komponen editor untuk kode sumber, saya benar-benar menginginkan cara agar editor itu menyorot sintaks yang diketiknya. Ada proyek seperti ini, seperti CodeMirror , Ace , dan Monaco , tetapi semuanya adalah editor kelas berat dengan fitur lengkap, bukan hanya area teks yang dapat diedit dengan penyorotan sintaks seperti yang saya inginkan.

Butuh sedikit penyelesaian, tetapi saya akhirnya membuat sesuatu yang melakukan pekerjaan itu dan ingin berbagi bagaimana saya melakukannya, karena ini melibatkan pengintegrasian perpustakaan penyorotan sintaks yang populer dengan kemampuan pengeditan HTML, serta beberapa kasus tepi yang menarik untuk dipertimbangkan. pertimbangan.

Silakan dan coba saat kita menggali!

Masalah

Pertama, saya mencoba menggunakan contenteditable pada div. Saya mengetik beberapa kode sumber ke div dan menjalankannya melalui Prism.js , penyorot sintaks yang populer, di onkeyup melalui JavaScript. Sepertinya ide yang bagus, bukan? Kami memiliki elemen yang dapat diedit di ujung depan, dan Prism.js menerapkan gaya sintaks untuk apa yang diketik di elemen.

Chris membahas cara menggunakan Prism.js dalam video ini .

Tapi itu tidak boleh dilakukan. Setiap kali konten dalam elemen berubah, DOM dimanipulasi dan kursor pengguna didorong kembali ke awal kode , yang berarti kode sumber muncul ke belakang, dengan karakter terakhir di awal, dan karakter pertama di akhir.

Teks spasi tunggal berwarna putih dengan latar belakang hitam yang tidak mengeja kata yang koheren.
Kode mundur: tidak terlalu berguna

Selanjutnya, saya mencoba menggunakan <textarea> tetapi itu juga tidak berhasil, karena textarea hanya dapat berisi teks biasa . Dengan kata lain, kami tidak dapat mengatur gaya konten yang dimasukkan. Sebuah textarea tampaknya menjadi satu-satunya cara untuk mengedit teks tanpa bug yang tidak diinginkan – itu tidak membiarkan Prism.js melakukan tugasnya.

Prism.js bekerja jauh lebih baik ketika kode sumber dibungkus dengan <pre><code> tipikal – ini hanya kehilangan bagian persamaan yang dapat diedit.

Jadi, sepertinya tidak ada yang bekerja sendiri. Tapi, saya pikir, mengapa tidak keduanya?

Solusinya

Saya menambahkan kedua sintaks-disorot <pre><code> dan textarea ke halaman, dan membuat innerText isi <pre><code> mengubah onkeyup , menggunakan fungsi JavaScript. Saya juga menambahkan aria-hidden ke hasil <pre><code> sehingga pembaca layar hanya akan membaca apa yang dimasukkan ke dalam <textarea> alih-alih dibaca dengan keras dua kali.

 <textarea id="editing" onkeyup="update(this.value);"></textarea> <pre id="highlighting" aria-hidden="true"> <code class="language-html" id="highlighting-content"></code> </pre>
 function update(text) { let result_element = document.querySelector("#highlighting-content"); // Update code result_element.innerText = text; // Syntax Highlight Prism.highlightElement(result_element); }
HTML untuk elemen link yang mengarah ke CSS-Tricks berwarna monospace hitam dengan latar belakang putih di atas markup link HTML yang sama, tetapi disorot dengan sintaks di latar belakang hitam.
Sekarang dapat diedit dan disorot!

Sekarang, ketika textarea diedit – seperti pada, tombol yang ditekan pada keyboard muncul kembali – kode yang disorot sintaks berubah. Ada beberapa bug yang akan kita bahas, tetapi saya ingin fokus terlebih dahulu untuk membuatnya terlihat seperti Anda langsung mengedit elemen yang disorot sintaks, daripada textarea terpisah.

Membuatnya "terasa" seperti editor kode

Idenya adalah untuk menggabungkan elemen bersama-sama sehingga sepertinya kita berinteraksi dengan satu elemen ketika sebenarnya ada dua elemen yang bekerja. Kita dapat menambahkan beberapa CSS yang pada dasarnya memungkinkan elemen <textarea> dan <pre><code> diberi ukuran dan spasi secara konsisten.

 #editing, #highlighting { /* Both elements need the same text and space styling so they are directly on top of each other */ margin: 10px; padding: 10px; border: 0; width: calc(100% - 32px); height: 150px; } #editing, #highlighting, #highlighting * { /* Also add text styles to highlighting tokens */ font-size: 15pt; font-family: monospace; line-height: 20pt; }

Kemudian kami ingin memposisikannya tepat di atas satu sama lain:

 #editing, #highlighting { position: absolute; top: 0; left: 0; }

Dari sana, z-index memungkinkan textarea menumpuk di depan hasil yang disorot:

 /* Move the textarea in front of the result */ #editing { z-index: 1; } #highlighting { z-index: 0; }

Jika kita berhenti di sini, kita akan melihat bug pertama kita. Sepertinya Prism.js tidak menyoroti sintaks, tetapi itu hanya karena area textarea menutupi hasilnya.

Kemana perginya sorotan? (Petunjuk: Itu bersembunyi di latar belakang.)

Kami dapat memperbaikinya dengan CSS! Kami akan membuat <textarea> sepenuhnya transparan kecuali tanda sisipan (kursor):

 /* Make textarea almost completely transparent */ #editing { color: transparent; background: transparent; caret-color: white; /* Or choose your favorite color */ }

Ah, jauh lebih baik!

Markup HTML untuk elemen tautan yang mengarah ke trik CSS dalam font monospace yang disorot sintaks dengan latar belakang hitam.
Kemana tautan ini akan membawa Anda? Kamu putuskan.

Lebih banyak perbaikan!

Setelah saya sampai sejauh ini, saya bermain-main dengan editor dan dapat menemukan beberapa hal lagi yang perlu diperbaiki. Hal baiknya adalah semua masalah cukup mudah diperbaiki menggunakan JavaScript, CSS, atau bahkan HTML.

Hapus pemeriksaan ejaan asli

Kami membuat editor kode, dan kode memiliki banyak kata dan atribut yang akan dianggap oleh pemeriksa ejaan asli browser sebagai salah eja.

Menampilkan markup HTML dasar untuk tautan dengan penyorotan sintaks pada latar belakang hitam, dengan atribut href digarisbawahi dengan warna merah.

Memeriksa ejaan bukanlah hal yang buruk; itu hanya tidak membantu dalam situasi ini. Apakah ada yang ditandai salah karena ejaannya salah atau karena kodenya tidak valid? Sulit untuk mengatakannya. Untuk memperbaikinya, yang kita butuhkan hanyalah menyetel atribut spellcheck <textarea> ke false :

 <textarea id="editing" spellcheck="false" ...>

Menangani jalur baru

Ternyata innerText tidak mendukung baris baru ( \n ).

Teks monospace putih dengan latar belakang hitam. Baris pertama mengatakan "Halo, Dunia" dan baris kedua mengatakan "Dunia" dan disorot dengan warna biru.
Meskipun "Dunia!" harus berada di baris baru, bagian yang disorot sintaks menampilkannya di baris yang sama.

Fungsi update perlu diedit. Daripada menggunakan innerText , kita bisa mengganti karakter open bracket ( < ) dengan &lt; . Ini mencegah tag HTML baru dibuat, memungkinkan kode sumber yang sebenarnya ditampilkan alih-alih browser mencoba merender kode.

 result_element.innerHTML = text.replace(new RegExp("<", "g"), "<"); /* Global RegExp */
Menampilkan boilerplate dokumen HTML dasar dengan penyorotan sintaks pada latar belakang hitam. Elemen body berisi markup yo sebuah paragraf yang berisi link yang bertuliskan "CSS-Tricks is brilyan!"

Menggulir dan mengubah ukuran

Berikut hal lain: kode yang disorot tidak dapat digulir saat pengeditan sedang berlangsung. Dan saat textarea di-scroll, kode yang disorot tidak ikut tergulung.

Pertama, mari pastikan bahwa textarea dan hasil mendukung pengguliran:

 /* Can be scrolled */ #editing, #highlighting { overflow: auto; }

Kemudian, untuk memastikan bahwa hasilnya bergulir dengan textarea, kami akan memperbarui HTML dan JavaScript seperti ini:

 <textarea id="editing" onkeyup="update(this.value); sync_scroll(this);" onscroll="sync_scroll(this);"></textarea>
 function sync_scroll(element) { /* Scroll result to scroll coords of event - sync with textarea */ let result_element = document.querySelector("#highlighting"); // Get and set x and y result_element.scrollTop = element.scrollTop; result_element.scrollLeft = element.scrollLeft; }

Beberapa browser juga mengizinkan textarea diubah ukurannya, tetapi ini berarti textarea dan hasilnya bisa menjadi ukuran yang berbeda. Bisakah CSS memperbaiki ini? Tentu bisa. Kami hanya akan menonaktifkan pengubahan ukuran:

 /* No resize on textarea */ #editing { resize: none; }

Garis indentasi

Salah satu hal yang lebih sulit untuk disesuaikan adalah bagaimana menangani lekukan garis pada hasil. Cara editor saat ini disiapkan, membuat garis indentasi dengan spasi berfungsi dengan baik. Tapi, jika Anda lebih suka tab daripada spasi, Anda mungkin memperhatikan bahwa itu tidak berfungsi seperti yang diharapkan.

JavaScript dapat digunakan untuk membuat tombol Tab berfungsi dengan baik. Saya telah menambahkan komentar untuk memperjelas apa yang terjadi di fungsi tersebut.

 <textarea ... onkeydown="check_tab(this, event);"></textarea>
 function check_tab(element, event) { let code = element.value; if(event.key == "Tab") { /* Tab key pressed */ event.preventDefault(); // stop normal let before_tab = code.slice(0, element.selectionStart); // text before tab let after_tab = code.slice(element.selectionEnd, element.value.length); // text after tab let cursor_pos = element.selectionEnd + 2; // where cursor moves after tab - 2 for 2 spaces element.value = before_tab + " " + after_tab; // add tab char - 2 spaces // move cursor element.selectionStart = cursor_pos; element.selectionEnd = cursor_pos; } }

Hasil akhir

Tidak terlalu gila, bukan? Yang kita miliki hanyalah <textarea> , <pre> dan <code> di HTML, baris baru CSS yang menumpuknya, dan pustaka penyorot sintaks untuk memformat apa yang dimasukkan. Dan yang paling saya sukai dari hal ini adalah kami bekerja dengan elemen HTML semantik yang normal, memanfaatkan atribut asli untuk mendapatkan perilaku yang kami inginkan, mengandalkan CSS untuk menciptakan ilusi bahwa kami hanya berinteraksi dengan satu elemen, lalu meraihnya. JavaScript untuk menyelesaikan beberapa kasus edge.

Sementara saya menggunakan Prism.js untuk penyorotan sintaks, teknik ini akan bekerja dengan yang lain. Ia bahkan akan bekerja dengan penyorot sintaks yang Anda buat sendiri, jika Anda menginginkannya. Saya harap ini menjadi berguna, dan dapat digunakan di banyak tempat, apakah itu editor WYSIWYG untuk CMS, atau bahkan formulir di mana kemampuan untuk memasukkan kode sumber adalah persyaratan seperti lamaran pekerjaan front-end atau mungkin kuis. Bagaimanapun, ini adalah <textarea> , sehingga dapat digunakan dalam bentuk apa pun – Anda bahkan dapat menambahkan placeholder jika perlu!


Postingan Membuat Area Teks yang Dapat Diedit yang Mendukung Kode yang Disorot Sintaksis muncul pertama kali di CSS-Tricks .

Anda dapat mendukung CSS-Tricks dengan menjadi Supporter MVP .

April 17, 2021

codeorayo

Ampuh! Ini rahasia mengembangkan aplikasi secara instan, tinggal download dan kembangkan. Gabung sekarang juga! Premium Membership [PRIVATE] https://premium.codeorayo.com

Leave a Reply

Your email address will not be published. Required fields are marked *