Editor penurunan harga yang menyempurnakan area teks Anda alih-alih menggantinya, sehingga pengiriman formulir, validasi, dan bidang wajib tetap berfungsi. WYSIWYG dan mode Markdown biasa, pratinjau langsung, temukan & ganti, dukungan RTL, mode gelap. Bekerja mandiri dengan Django, Laravel, Rails, Node.js, PHP, dan tumpukan apa pun.
Tidak memerlukan Frutjam dan Tailwind. Gayanya dibundel, sehingga editor dapat langsung mengerjakan proyek apa pun.
Instalasi
NPM (bundel: Vite, webpack, Rollup, dll.)
npm install markdown-text-editor |
1 2 | import MarkdownEditor from 'markdown-text-editor'; new MarkdownEditor('#markdown-editor'); |
Definisi TypeScript dikirimkan bersama paket, sehingga opsi, entri toolbar, dan bentuk variabel diperiksa dan dilengkapi secara otomatis tanpa instalasi tambahan.
CDN: modul ES
1 2 3 4 | <script type="module"> import MarkdownEditor from 'https://cdn.jsdelivr.net/npm/markdown-text-editor/+esm'; new MarkdownEditor('#markdown-editor'); </script> |
CDN: tag skrip global (IIFE)
Tidak perlu impor: MarkdownEditor tersedia sebagai variabel global secara otomatis.
1 2 3 4 5 6 7 8 9 | <form action="/api/save" method="POST"> <textarea id="markdown-editor" name="content"># Hello World</textarea> <button type="submit">Save Content</button> </form> <script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script> <script> new MarkdownEditor('#markdown-editor'); </script> |
Demo Editor Penurunan Harga
Mulai Cepat
Berikan objek opsi untuk menyesuaikan editor. Semua opsi bersifat opsional: hilangkan opsi apa pun untuk menggunakan nilai default.
1 2 3 4 | const editor = new MarkdownEditor('#markdown-editor', { placeholder: 'Write your markdown...', toolbar: ['heading', 'bold', 'italic', 'strikethrough', 'ul', 'ol', 'checklist', 'blockquote', 'link', 'preview'], }); |
Filosofi: "Pribumi-Pertama"
Kebanyakan editor melanggar alur kerja web standar. MarkdownEditor menerimanya. Karena letaknya tepat di atas a <textarea>, Anda tidak perlu mempelajari cara baru untuk menangani data.
- Tidak Perlu Pengikatan Data: Dapat digunakan dengan
<form method="POST">di luar kotak - Akses Standar: Gunakan
document.getElementById('editor').valueseperti masukan biasa. - Backend Agnostic: Berfungsi dengan backend apa pun (Python, Node.js, PHP, dll.) seperti kolom formulir normal
MarkdownEditor vs EasyMDE / SimpleMDE
Kebanyakan editor penurunan harga JavaScript (EasyMDE, SimpleMDE, editor berbasis CodeMirror) menyembunyikan Anda <textarea> dan edit salinannya, tulis kembali isinya saat formulir diserahkan. Itu berfungsi sampai sesuatu yang lain membutuhkan nilai: a required bidang browser tidak dapat fokus memblokir pengiriman seluruhnya, dan .value atau FormData read before submit mengembalikan string kosong, yang merusak penjaga htmx, Turbo, penyimpanan otomatis, dan perubahan yang belum disimpan. MarkdownEditor berbeda. Ini memberi gaya pada area teks yang sudah Anda miliki dan membiarkannya sebagai bidang yang Anda ketik, sehingga nilainya selalu benar.
| Fitur | Editor Penurunan Harga | MudahMDE / SederhanaMDE |
|---|---|---|
| Textarea asli dipertahankan | ✅ | ❌ Tersembunyi, diedit sebagai salinan |
Bekerja dengan required bidang | ✅ | ❌ Browser memblokir pengiriman |
.value benar sebelum diserahkan | ✅ | ❌ Kosongkan sampai formulir dikirimkan |
Serialisasi dengan FormData, htmx, Turbo | ✅ | ❌ Memerlukan API milik editor sendiri |
| Mode hibrid WYSIWYG | ✅ | ❌ |
| Temukan & Ganti bawaan | ✅ | ❌ |
| dukungan RTL | ✅ Terpasang | Melalui CodeMirror's direction pilihan |
| Pengendali kejadian sebaris (CSP) | ✅ Tidak ada | Beberapa |
| Mode gelap/tema | ✅ | Terbatas |
| Ukuran bundel, di-gzip | 53KB | 107 KB (JS+CSS) |
Integrasi Kerangka
Karena MarkdownEditor mempertahankan yang asli <textarea>, ini terintegrasi dengan setiap kerangka backend tanpa kode tambahan apa pun. Server Anda menerima konten penurunan harga persis seperti yang diterima dari bidang formulir standar mana pun. Untuk React dan Vue dibutuhkan beberapa baris, yang dibahas di akhir bagian ini.
Django
Tambahkan sebuah class ke widget textarea Anda dan inisialisasi editor: request.POST['content'] bekerja tanpa langkah tambahan.
1 2 3 4 5 6 7 8 | # forms.py class PostForm(forms.ModelForm): class Meta: model = Post fields = ['content'] widgets = { 'content': forms.Textarea(attrs={'class': 'markdown-editor'}), } |
1 2 | new MarkdownEditor('.markdown-editor'); // request.POST['content'] contains the markdown on submit |
Laravel
Menggunakan f.text_area dengan kelas: $request->input('content') menerima penurunan harga secara langsung.
1 2 | <textarea name="content" class="markdown-editor">{{ old('content') }}</textarea> <script>new MarkdownEditor('.markdown-editor');</script> |
Ruby di Rel
Bekerja dengan form_with di luar kotak: params[:content] berisi penurunan harga. Untuk Turbo Drive, gunakan turbo:load alih-alih DOMContentLoaded.
1 2 3 4 5 6 | document.addEventListener('turbo:load', () => { document.querySelectorAll('.markdown-editor:not([data-mde-init])').forEach(el => { el.setAttribute('data-mde-init', 'true'); new MarkdownEditor(el); }); }); |
Node.js / Ekspres
req.body.content menerima penurunan harga pada pengiriman formulir: tidak ada langkah sinkronisasi, tidak ada ekstraksi khusus.
1 2 3 | <textarea name="content" class="markdown-editor"></textarea> <script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script> <script>new MarkdownEditor('.markdown-editor');</script> |
PHP
$_POST['content'] berfungsi persis seperti area teks standar mana pun: masukkan dan penanganan formulir yang ada tidak memerlukan perubahan apa pun.
1 2 3 4 5 6 | <form method="POST" action="save.php"> <textarea name="content" class="markdown-editor"></textarea> <button type="submit">Save</button> </form> <script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script> <script>new MarkdownEditor('.markdown-editor');</script> |
Bereaksi
Buat editor dalam sebuah efek dan hancurkan saat melepasnya. Menggunakan defaultValue daripada value: editor menulis ke textarea secara langsung, sehingga pengikatan terkontrol akan menimpa apa yang diketik pengguna.
1 2 3 4 5 6 7 8 9 10 11 12 13 | import { useEffect, useRef } from 'react'; import MarkdownEditor from 'markdown-text-editor'; function MarkdownField({ name, defaultValue = '', onChange }) { const ref = useRef(null); useEffect(() => { const editor = new MarkdownEditor(ref.current, { onChange }); return () => editor.destroy(); }, []); return <textarea ref={ref} name={name} defaultValue={defaultValue} />; } |
Kembali editor.destroy() dari efeknya juga mencakup StrictMode, yang menjalankan efek dua kali dalam pengembangan dan jika tidak, akan meninggalkan dua editor pada satu area teks. Array ketergantungan yang kosong memang disengaja: opsi dibaca satu kali ketika editor dibuat, jadi menjalankan kembali efeknya akan menghancurkannya dan membangunnya kembali pada setiap perubahan.
Lihat
Ide yang sama. Tetapkan nilai awal sekali masuk onMounted dan tidak mengikat :value, atau setiap penekanan tombol yang dipancarkan kembali v-model akan menimpa textarea.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <script setup> import { ref, onMounted, onBeforeUnmount } from 'vue'; import MarkdownEditor from 'markdown-text-editor'; const el = ref(null); const props = defineProps({ modelValue: { type: String, default: '' } }); const emit = defineEmits(['update:modelValue']); let editor = null; onMounted(() => { el.value.value = props.modelValue; editor = new MarkdownEditor(el.value, { onChange: value => emit('update:modelValue', value) }); }); onBeforeUnmount(() => editor?.destroy()); </script> <template><textarea ref="el"></textarea></template> |
Digunakan sebagai <MarkdownField v-model="content" />. Dalam bentuk biasa Anda bisa melewatinya v-model seluruhnya dan membaca nilai dari textarea saat dikirimkan, seperti halnya kerangka kerja lainnya.
Konfigurasi
Anda dapat sepenuhnya menyesuaikan perilaku dan antarmuka editor dengan meneruskan options obyek. Jika Anda menghilangkan opsi, nilai default akan digunakan.
Opsi dibaca satu kali, saat editor dibuat. Mengubahnya setelahnya tidak berpengaruh: call destroy() dan buat editor baru sebagai gantinya.
| Milik | Jenis | Bawaan | Tujuan |
|---|---|---|---|
mode | string | 'plain' | Mengatur tampilan awal. Gunakan hybrid untuk pengalaman WYSIWYG atau biasa untuk sintaks mentah. |
placeholder | string | 'Write...' | Teks ditampilkan saat editor kosong. |
toolbar | array | [...] | Menentukan alat mana yang muncul dan dalam urutan apa. |
footer | salah | objek | semua terlihat | Mengontrol bilah status yang ditampilkan di bawah editor. Setel ke false untuk menyembunyikannya seluruhnya, atau meneruskan objek untuk mengubah statistik individual. |
theme | string | inherited | Menetapkan tema editor secara eksplisit (terang, gelap, snowberry, darkberry). Jika dihilangkan, editor mewarisi data-theme dari elemen leluhur terdekat atau <textarea> diri. |
minHeight | number | 200 | Tinggi minimum dalam piksel yang akan diperkecil oleh editor ketika kontennya pendek. Pasangkan dengan maxHeight untuk mengatur rentang pertumbuhan otomatis. |
maxHeight | number | 500 | Tinggi maksimum dalam piksel yang dapat ditingkatkan editor dalam mode non-layar penuh. Setelah konten melebihi ketinggian ini, bilah gulir akan muncul di dalam editor. Editor juga memiliki pegangan tarik sehingga pengguna dapat mengubah ukurannya secara manual melebihi batas ini. |
renderer | function | marked | Menggantikan parser penurunan harga yang digunakan untuk pratinjau. Menerima string penurunan harga dan harus mengembalikan string HTML. |
sanitizer | function | DOMPurify | Menggantikan pembersih HTML. Menerima HTML yang dirender dan harus mengembalikan HTML aman untuk ditampilkan. |
onChange | function | undefined | Callback diaktifkan pada setiap perubahan konten: pengetikan, tindakan toolbar, undo/redo, dan kelanjutan daftar. Menerima string penurunan harga saat ini sebagai satu-satunya argumennya. |
labels | object | undefined | Terjemahan untuk antarmuka editor sendiri, dikunci dengan string bahasa Inggris. Apa pun yang Anda tinggalkan akan tetap dalam bahasa Inggris. |
🛠 Kustomisasi Bilah Alat
Bilah alatnya bersifat modular. Anda dapat menciptakan pengalaman minimal atau power suite berfitur lengkap dengan memodifikasi array.
Alat yang Tersedia
| Kategori | Kunci Alat |
|---|---|
| Tipografi | heading, bold, italic, strikethrough, blockquote |
| Daftar | ul (bullet), ol (numbered), checklist |
| Kode | code (sebaris), codeblock (blok berpagar) |
| Sisipan | hr (aturan horizontal), table (templat tabel) |
| Media | link, image |
| Mengedit | undo, redo, indent, outdent |
| Melihat | preview |
| Templat | { variables: [...] }, dikonfigurasi sebaris |
Referensi Alat
| Alat | Keterangan |
|---|---|
heading | Membuka tarik-turun untuk memilih tingkat judul H1–H6 |
bold | Mengaktifkan pemformatan teks tebal. |
italic | Mengaktifkan pemformatan teks miring. |
strikethrough | Memungkinkan teks dicoret. |
ol | (Daftar Terurut): Mengubah teks menjadi format daftar bernomor. |
ul | (Daftar Tidak Berurutan): Mengubah teks menjadi daftar poin-poin. |
checklist | Menambahkan kotak centang ke teks Anda, sehingga cocok untuk tugas, daftar tugas, atau melacak status penyelesaian. |
blockquote | Sorot teks yang dikutip atau ditekankan. |
code | Membungkus teks yang dipilih dalam satu backtick untuk kode sebaris. Mengklik lagi akan menghapus backticks. |
codeblock | Membungkus teks yang dipilih dalam blok kode berpagar triple-backtick. Mengklik lagi akan menghilangkan pagar. |
hr | Sisipan a --- aturan horizontal pada posisi kursor pada barisnya sendiri. |
table | Menyisipkan templat tabel penurunan harga 2x3 awal pada posisi kursor. |
image | Memungkinkan Anda menyisipkan gambar melalui sintaks penurunan harga. |
link | Memungkinkan Anda menambahkan hyperlink ke teks Anda. |
undo | Untuk membalikkan perubahan terakhir. |
redo | Untuk menerapkan kembali perubahan terakhir yang dibatalkan. |
indent | Untuk meningkatkan tingkat lekukan. |
outdent | Untuk mengurangi tingkat lekukan. |
preview | Mengalihkan pratinjau layar penuh berdampingan. Kotak centang di panel pratinjau dapat diklik dan memperbarui sumber penurunan harga secara instan. Tekan Escape untuk keluar dari layar penuh. Jika header tetap menutupi editor dalam layar penuh, lihat --mte-fullscreen-z-index. |
💡 Kiat Penerapan:
- Penyusunan Ulang: Tombol muncul sesuai urutan yang Anda cantumkan dalam larik
- Menghapus: Cukup hilangkan tombol apa saja (seperti
image) dari array untuk menonaktifkan fitur tersebut sepenuhnya bagi pengguna - Pengembalian Asli: Jika Anda tidak memberikan
placeholderdi JS, plugin akan secara otomatis menggunakanplaceholderatribut dari HTML Anda<textarea>
📊 Catatan Kaki (Bilah Status)
Footer berada di bawah editor dan menampilkan baris, kolom kursor, jumlah karakter dokumen, dan opsional jumlah kata, semuanya diperbarui secara real-time. Ini terlihat secara default dan setiap stat dapat diubah secara independen.
| Kunci | Jenis | Bawaan | Keterangan |
|---|---|---|---|
line | boolean | true | Tampilkan nomor baris saat ini. |
col | boolean | true | Tampilkan nomor kolom saat ini. |
chars | boolean | true | Tampilkan jumlah karakter total. |
words | boolean | false | Tunjukkan jumlah kata total. Nonaktif secara default: disetel ke true untuk mengaktifkan. |
Contoh Penggunaan
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // Default — line, col, and chars visible new MarkdownEditor('#editor'); // Disable the footer entirely new MarkdownEditor('#editor', { footer: false }); // Hide only character count new MarkdownEditor('#editor', { footer: { chars: false } }); // Hide line and column, keep character count new MarkdownEditor('#editor', { footer: { line: false, col: false } }); // Show only line number new MarkdownEditor('#editor', { footer: { col: false, chars: false } }); // Enable word count alongside the defaults new MarkdownEditor('#editor', { footer: { words: true } }); // Show word count only new MarkdownEditor('#editor', { footer: { line: false, col: false, chars: false, words: true } }); |
🔀 Mode Pengeditan
MarkdownEditor menawarkan dua cara berbeda untuk menulis dan memformat konten Anda. Anda dapat beralih antara tampilan tradisional yang berfokus pada sintaksis atau pengalaman modern yang mengutamakan visual.
plain(Default): Lingkungan penurunan harga yang bersih dan berkinerja tinggi dengan sintaksis (seperti**bold**atau# heading) terlihat. Ideal untuk pengembang dan penganut penurunan hargahybrid: Pengalaman yang terinspirasi WYSIWYG yang menampilkan pemformatan (Tebal, Miring, Judul) secara real-time saat Anda mengetik, sambil tetap mempertahankan struktur penurunan harga yang mendasarinya.
1 2 3 4 5 6 7 8 9 10 11 12 | // Default initialization (Plain Mode) new MarkdownEditor('#markdown-editor'); // Explicit Plain Mode new MarkdownEditor('#markdown-editor', { mode: 'plain' }); // Hybrid (Visual) Mode new MarkdownEditor('#markdown-editor', { mode: 'hybrid' }); |
Pratinjau Mode Hibrid dan Biasa:
Modus Hibrida
Pemformatan visual ditampilkan secara real-time saat Anda mengetik.
Mode Biasa (Default)
Berfokus pada sintaks penurunan harga mentah untuk pengalaman yang ringan.
🌙 Tema
MarkdownEditor secara otomatis mewarisi temanya dari halaman sekitarnya: tidak diperlukan konfigurasi. Editor membaca data-theme dari nenek moyang terdekat saat inisialisasi, sehingga tetap sinkron dengan tema situs Anda.
Bagaimana tema diselesaikan (urutan prioritas)
themeoption: penggantian eksplisit yang diteruskan pada objek opsidata-themedi<textarea>: disetel langsung pada elemendata-themepada leluhur mana pun: mis.<html>,<body>, atau pembungkus<div>
Tema yang tersedia
'light' (bawaan), 'dark', 'snowberry', 'darkberry'
Opsi 1, mewarisi dari <html> atau leluhur mana pun (konfigurasi nol)
1 2 3 4 5 6 | <html data-theme="dark"> ... <textarea id="markdown-editor"></textarea> <script> new MarkdownEditor('#markdown-editor'); // picks up dark automatically </script> |
Opsi 2: atur data-theme langsung di <textarea>
1 2 3 4 | <textarea id="markdown-editor" data-theme="dark"></textarea> <script> new MarkdownEditor('#markdown-editor'); </script> |
Opsi 3: eksplisit theme opsi (mengesampingkan semuanya)
1 2 3 | new MarkdownEditor('#markdown-editor', { theme: 'dark' }); |
🎨 Tema Khusus melalui Variabel CSS
Anda dapat sepenuhnya menyesuaikan tampilan editor dengan mengganti variabel CSS-nya di .markdown-editor-wrapper elemen atau apa pun [data-theme] pemilih. Semua warna menggunakan Ruang warna OKLCH untuk hasil yang seragam secara persepsi.
| Variabel | Tujuan | Standar ringan | Defaultnya gelap |
|---|---|---|---|
--color-base | Latar belakang penyunting | oklch(100% 0 0) | oklch(10.9% 0 0) |
--color-on-base | Warna teks utama | oklch(22% 0 0) | oklch(98% 0 0) |
--color-primary | Aksen utama (bilah alat aktif, tautan) | oklch(51.1% .262 277) | oklch(66.4% .184 286) |
--color-on-primary | Teks pada permukaan berwarna primer | oklch(96.2% .018 272) | oklch(10% .01 270) |
--color-secondary | Aksen sekunder | oklch(59.1% .293 323) | oklch(65% .18 220) |
--color-accent | Aksen highlight (kode sebaris, miring) | oklch(54.1% .281 293) | oklch(75% .18 50) |
--color-neutral | Permukaan netral (batas, pemisah) | oklch(15% 0 0) | oklch(85% 0 0) |
--color-error | Warna status kesalahan | oklch(57.7% .245 27) | oklch(60% .22 30) |
--border-radius | Pembulatan sudut bingkai editor | 0.25rem |
Contoh tema khusus
Ganti variabel apa pun aktif .markdown-editor-wrapper setelah editor menginisialisasi, atau menentukan kebiasaan [data-theme] blok di stylesheet Anda:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* Override individual variables */ .markdown-editor-wrapper { --color-primary: oklch(60% 0.2 30); /* orange accent */ --border-radius: 0.5rem; } /* Or define a full custom theme */ [data-theme="brand"] .markdown-editor-wrapper, .markdown-editor-wrapper[data-theme="brand"] { --color-base: oklch(15% 0.01 250); --color-on-base: oklch(95% 0 0); --color-primary: oklch(65% 0.22 145); /* green */ --color-on-primary: oklch(10% 0 0); --color-accent: oklch(75% 0.18 60); --color-neutral: oklch(80% 0 0); --border-radius: 0.75rem; } |
new MarkdownEditor('#markdown-editor', { theme: 'brand' }); |
🌐 Bahasa Antarmuka
Teks, keterangan alat, item menu, bidang modal, dan tombol milik editor, secara default adalah bahasa Inggris. Lulus a labels keberatan untuk menerjemahkannya. Kuncinya adalah string bahasa Inggris, cara kerja gettext, jadi Anda hanya mencantumkan apa yang ingin Anda ubah dan apa pun yang hilang akan dikembalikan ke bahasa Inggris.
1 2 3 4 5 6 7 8 9 10 11 12 13 | new MarkdownEditor('#markdown-editor', { labels: { 'Bold': 'Gras', 'Italic': 'Italique', 'Heading': 'Titre', 'Link': 'Lien', 'Image link': 'Lien de l\'image', 'URL': 'URL', 'Alt text': 'Texte alternatif', 'Apply': 'Appliquer', 'Uploading...': 'Téléversement...', }, }); |
Hal ini paling penting dibandingkan dengan konten kanan-ke-kiri. Bahasa Arab, Urdu, dan Farsi ditata dengan benar, namun bilah alat yang masih bertuliskan "Tebal" di atas teks dari kanan ke kiri hanya setengah diterjemahkan.
🏷 Variabel
Menambahkan dropdown toolbar untuk menyisipkan placeholder. Berguna ketika orang yang menulis dokumen bukanlah pengembang yang mendefinisikan sintaksis placeholder, seperti email, faktur, atau templat kontrak: mereka memilih nama yang dapat dibaca dan sintaksis yang benar dimasukkan untuk mereka.
1 2 3 4 5 6 7 8 9 | new MarkdownEditor('#markdown-editor', { toolbar: ['bold', 'italic', 'link', { variables: [ { label: 'Customer Name', value: '{{customer.name}}' }, { label: 'Invoice No', value: '{{invoice.number}}' } ]}, 'preview' ] }); |
Alat ini dikonfigurasi secara inline di toolbar array, jadi posisinya di antara tombol-tombol lainnya terserah Anda. Tombol tersebut mencantumkan label, dan mengklik salah satu label akan menyisipkannya value di kursor, menggantikan pilihan apa pun. Tidak ada yang ditampilkan jika daftarnya kosong.
Contoh nilai di pratinjau
Entri yang diberikan a sample menunjukkan sampel itu di pratinjau, sementara area teks menyimpan placeholder sebenarnya. Entri tanpa satu pun akan muncul seperti tertulis, sehingga Anda dapat menggabungkan keduanya.
1 2 3 4 5 6 7 | { variables: [ { label: 'Customer Name', value: '{{customer.name}}', sample: 'Hannes' }, { label: 'Invoice No', value: '{{invoice.number}}' } ]} // textarea : Hi {{customer.name}}, invoice {{invoice.number}} // preview : Hi Hannes, invoice {{invoice.number}} |
Pengelompokan
Berikan entri items bukannya a value untuk membuat bagian yang dituju. Entri yang dikelompokkan dan datar dapat dicampur dalam satu daftar.
1 2 3 4 5 6 7 8 9 10 | { variables: [ { label: 'Today', value: '{{today}}', sample: '10 September 2026' }, { label: 'Customer', items: [ { label: 'Name', value: '{{customer.name}}', sample: 'Hannes' }, { label: 'Email', value: '{{customer.email}}', sample: 'hannes@example.com' } ]}, { label: 'Invoice', items: [ { label: 'Number', value: '{{invoice.number}}' } ]} ]} |
Hal yang perlu diketahui
- Editor tidak pernah menyelesaikan variabel. Editor menyisipkan teks, dan aplikasi Anda kemudian menggantikan nilai sebenarnya, biasanya di sisi server.
samplehanya memengaruhi apa yang ditampilkan pratinjau. - Label ditampilkan sebagai teks biasa, sehingga markup dalam label tidak pernah dirender.
- Entri yang formatnya salah akan dilewati alih-alih dilempar, dan tombol tidak ditampilkan sama sekali saat tidak ada konfigurasi yang dapat digunakan.
🖋 Perender Khusus
Pratinjau dirender dengan ditandai dan disanitasi dengan DOMPurifikasi. Keduanya bisa diganti. Gunakan ini ketika aplikasi Anda sudah merender penurunan harga dengan pustaka lain dan Anda ingin pratinjaunya sama persis dengan produksi.
Kedua opsi tersebut merupakan fungsi biasa yang mengambil string dan mengembalikan string, sehingga parser dan pembersih apa pun dapat berfungsi.
1 2 3 4 5 6 7 8 9 | import MarkdownIt from 'markdown-it'; import taskLists from 'markdown-it-task-lists'; import MarkdownEditor from 'markdown-text-editor'; const md = new MarkdownIt({ linkify: true, breaks: true }).use(taskLists); new MarkdownEditor('#markdown-editor', { renderer: markdown => md.render(markdown) }); |
DOMPurify masih berjalan pada output, jadi Anda tetap melindungi XSS tanpa mengonfigurasi apa pun.
Pembersih khusus
Hanya diperlukan ketika default menghapus sesuatu yang dikeluarkan oleh penyaji Anda. DOMPurify menghapus <iframe> secara default, jadi penyematan video perlu diizinkan secara eksplisit. DOMPurify harus diimpor dalam kode Anda sendiri, karena salinan yang dibundel dengan editor bersifat internal.
1 2 3 4 5 6 7 8 9 | import DOMPurify from 'dompurify'; new MarkdownEditor('#markdown-editor', { renderer: markdown => md.render(markdown), sanitizer: html => DOMPurify.sanitize(html, { ADD_TAGS: ['iframe'], ADD_ATTR: ['allow', 'allowfullscreen', 'frameborder'] }) }); |
Dengan menggunakan tag skrip dan bukan bundler, muat DOMPurify bersama editor:
1 2 | <script src="https://cdn.jsdelivr.net/npm/dompurify"></script> <script src="https://cdn.jsdelivr.net/npm/markdown-text-editor"></script> |
Hal yang perlu diketahui
- Hanya pratinjau. Pemformatan langsung mode hibrid menggunakan perender internal terpisah dan tidak terpengaruh.
- Daftar tugas memerlukan dukungan plugin. Kotak centang yang dapat diklik ditemukan dengan mencari
input[type="checkbox"]dalam output, jadi penurunan harga diperlukanmarkdown-it-task-lists. Editor mencatat peringatan jika mendeteksi sintaksis daftar tugas dan tidak ada kotak centang. - Keduanya harus sinkron dan mengembalikan string. Sebuah
asyncfungsi menulis[object Promise]ke dalam pratinjau. - Mengganti pembersih menggantikan perlindungan Anda. Sebuah pass-through seperti
html => htmlmenonaktifkan sanitasi sepenuhnya dan hanya aman untuk konten yang sepenuhnya tepercaya.
🎨 Menata Elemen Internal
Variabel CSS mencakup sebagian besar tema karena merupakan warisan, jadi aktifkan salah satunya .markdown-editor-wrapper mencapai toolbar, tombol, pratinjau dan footer. Raih nama kelas hanya ketika tidak ada variabel yang memaparkan apa yang Anda butuhkan.
1 2 3 4 5 | /* Variables set on the wrapper inherit down to every child */ .markdown-editor-wrapper { --border-radius: 12px; /* rounds the editor and its toolbar buttons */ --color-primary: oklch(60% 0.2 30); } |
Referensi kelas
Nama kelas ini stabil dan aman untuk digunakan.
| Kelas | Elemen |
|---|---|
.markdown-editor-wrapper | Wadah luar membungkus seluruh editor |
.toolbar | Strip toolbar di atas area pengeditan |
.markdown-btn | Tombol bilah alat individual |
.preview-btn | Tombol sakelar pratinjau / layar penuh |
.editor-layout | Kisi yang menahan area pengeditan dan pratinjau secara berdampingan |
.textarea-wrapper | Bungkus di sekitar area pengeditan |
.editor-textarea | Elemen textarea yang mendasarinya |
.display-layer | Lapisan pemformatan yang dirender, hanya mode hibrid |
.preview-wrapper | Kolom pratinjau |
.preview-content | Penurunan harga yang diberikan di dalam pratinjau |
.editor-footer | Bilah status di bawah editor |
.find-replace-panel | Temukan dan ganti panel |
1 2 3 4 5 6 7 8 9 10 | /* Some variables are set by the component on itself, which beats an inherited value. Target the element directly for those. */ .markdown-editor-wrapper .markdown-btn { --btn--font-size: 0.875rem; } /* And use classes for anything no variable exposes */ .markdown-editor-wrapper .toolbar { border-bottom: 2px solid oklch(60% 0.2 30); } |
Menargetkan satu editor
Dengan beberapa editor dalam satu halaman, targetkan salah satunya dengan data-editor. Pembungkusnya mencerminkan idnya <textarea>, Jadi <textarea id="notes"> memberimu [data-editor="notes"]. Id itu sendiri tetap berada di textarea, jadi getElementById terus bekerja.
1 2 3 4 | /* one editor only */ [data-editor="notes"] { --border-radius: 0; } |
🪟 Layar Penuh & Lapisan (indeks-z)
Dalam layar penuh editor menggunakan z-index: 10000, yang menghapus lapisan yang dicadangkan sebagian besar kerangka UI untuk header dan overlay tetap. Jika header atau sidebar tetap masih menutupi editor, naikkan nilai ini.
Timpa dengan --mte-fullscreen-z-index. Nilai ini hanya berlaku di layar penuh, dan diwariskan, jadi menetapkannya pada leluhur mana pun akan mencakup setiap editor di bawahnya.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* every editor on the page */ .markdown-editor-wrapper { --mte-fullscreen-z-index: 20000; } /* one section only - the value inherits down */ #admin-panel { --mte-fullscreen-z-index: 20000; } /* a single editor, by its textarea id */ [data-editor="notes"] { --mte-fullscreen-z-index: 20000; } |
Api Konten
Salah satu kekuatan inti MarkdownEditor adalah bahwa ia mempertahankan <textarea> disinkronkan dengan sempurna. Apakah Anda menggunakan kerangka kerja JavaScript modern atau backend tradisional seperti Django, PHP, atau Laravel, alur kerjanya tetap sederhana dan asli.
Membaca dan Menulis Konten
1. Cara Asli (Disarankan)
Karena editor meningkatkan area teks standar, Anda dapat menggunakan metode DOM yang sudah dikenal. Ini adalah cara tercepat untuk berinteraksi dengan data Anda tanpa mempelajari api baru.
1 2 3 4 5 | // Retrieve content via ID const markdown = document.getElementById('markdown-editor').value; // Set content via ID (The editor UI updates automatically) document.getElementById('markdown-editor').value = "# New Heading Content"; |
2. Menggunakan Referensi Variabel
Jika Anda memiliki referensi ke elemen textarea, Anda dapat menggunakannya secara langsung: tidak diperlukan api khusus pustaka.
1 2 3 4 5 6 7 | const textarea = document.getElementById('markdown-editor'); // Retrieve content const markdown = textarea.value; // Set content (the editor UI reflects this immediately) textarea.value = "## Updated via JS"; |
3. Mengatur sisi server konten awal
Cara yang disarankan untuk mengatur konten awal adalah langsung di <textarea> HTML: ini bekerja secara alami dengan setiap kerangka kerja backend (Django, Laravel, Rails, PHP, dll.) dan editor merendernya secara otomatis pada init.
1 2 | <!-- Recommended: set content server-side --> <textarea id="markdown-editor"># Hello World</textarea> |
Untuk membaca atau memperbarui konten saat runtime, gunakan native textarea value. Telepon editor.render() setelah pembaruan untuk menyegarkan lapisan pratinjau dan hibrida.
1 2 3 4 5 6 7 8 | const textarea = document.getElementById('markdown-editor'); // Read const markdown = textarea.value; // Update at runtime textarea.value = '# New content'; editor.render(); |
4. Menghancurkan editor: destroy()
Panggilan editor.destroy() untuk menghapus pembungkus DOM editor dan mengembalikan yang asli <textarea> ke posisinya dalam dokumen. Berguna dalam aplikasi satu halaman saat melepas tampilan.
1 2 3 4 | const editor = new MarkdownEditor('#markdown-editor'); // Remove the editor and restore the plain textarea editor.destroy(); |
Bereaksi terhadap perubahan dengan onChange
Lulus sebuah onChange panggilan balik untuk diberitahu tentang setiap perubahan konten. Menerima string penurunan harga saat ini.
1 2 3 4 5 | const editor = new MarkdownEditor('#markdown-editor', { onChange(value) { console.log('Content changed:', value.length, 'characters'); } }); |
Draf simpan otomatis dengan localStorage
Menggunakan onChange untuk menyimpan draf pada setiap penekanan tombol. Pulihkan dengan mengisi terlebih dahulu area teks sebelum menginisialisasi editor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | const DRAFT_KEY = 'my-page-draft'; // Restore saved draft before init (only if textarea starts empty) const textarea = document.getElementById('markdown-editor'); const saved = localStorage.getItem(DRAFT_KEY); if (saved && !textarea.value) textarea.value = saved; // Save on every change const editor = new MarkdownEditor('#markdown-editor', { onChange(value) { localStorage.setItem(DRAFT_KEY, value); } }); // Clear draft after successful form submission document.querySelector('form').addEventListener('submit', () => { localStorage.removeItem(DRAFT_KEY); }); |
Pengiriman Formulir
Karena MarkdownEditor dibuat langsung dari versi asli <textarea>, ini kompatibel dengan setiap kerangka backend (Django, Laravel, PHP, Ruby on Rails, dll.) langsung dari kotaknya.
Di sinilah filosofi “Pribumi-Pertama” bersinar. Anda tidak perlu menyinkronkan data secara manual sebelum mengirimkan formulir. Browser memperlakukan editor persis seperti kolom input standar.
1 2 3 4 5 6 7 8 9 10 11 12 | <form method="POST" action="/api/submit"> <textarea id="markdown-editor" name="content" class="h-48" rows="5"> # Initial Content </textarea> <button type="submit">Submit to Server</button> </form> <script> // Just initialize it. That's it. new MarkdownEditor('#markdown-editor'); </script> |
Catatan: Inisialisasi plugin MarkdownEditor wajib
Cukup gunakan HTML standar <form>. Itu name Atribut pada textarea adalah apa yang akan digunakan server Anda untuk mengidentifikasi konten.
🚀 Mengapa ini merupakan Game-Changer untuk Backend
Karena editor mempertahankan aslinya <textarea> perilaku, server Anda menangani data sebagai string standar. Tidak diperlukan logika tambahan: tidak preventDefault() dan tidak ada panduannya FormData konstruksi.
💡 Mengapa ini disebut "Fitur Pembunuh":
Kebanyakan editor (seperti Quill, Editor.js, simpleMDE, easyMDE) menyimpan data dalam struktur JSON yang kompleks. Jika pengembang menggunakannya, mereka harus menulis ulang skema database dan logika renderingnya.
Dengan MarkdownEditor, pengembang dapat mengambil situs web lama, menggantikan yang biasa <textarea> dengan editor Anda, dan backend bahkan tidak mengetahui perubahannya. Itu hanya menerima teks mentah yang sama seperti biasanya, tetapi pengguna mendapatkan pengalaman 10x lebih baik.
| Kerangka / Bahasa | Cara mengakses konten penurunan harga |
|---|---|
| PHP | $_POST['content'] |
| Django | request.POST.get('content') |
| Node.js (Ekspres) | req.body.content |
| Laravel | $request->input('content') |
| Ruby di Rel | params[:content] |
🖼️ Unggah Gambar Tingkat Lanjut
Menangani unggahan gambar secara asli: daripada mengandalkan string Base64 yang lambat dan banyak memori, ini merupakan kemenangan yang signifikan baik untuk kinerja maupun SEO.
Tempel dan jatuhkan
Tempelkan tangkapan layar atau seret file gambar ke editor dan gambar tersebut akan diunggah melalui titik akhir yang sama dengan tombol toolbar. Placeholder segera muncul sehingga editor tidak pernah terlihat terhenti, dan digantikan dengan jalur sebenarnya setelah unggahan mendarat. Jika pengunggahan gagal, placeholder akan diganti dengan penanda yang terlihat, bukannya menghilang secara diam-diam.
Ini perlu uploadUrl dikonfigurasi di bawah ini. Tanpanya, menempelkan gambar tidak akan menghasilkan apa-apa dan editor mencatat peringatan yang menjelaskan apa yang harus ditambahkan, karena alternatifnya adalah string Base64 di database Anda.
Beberapa file sekaligus diunggah satu per satu, sehingga gambar masuk sesuai urutan kedatangannya.
Opsi Konfigurasi
Alat gambar mendukung a fileInput konfigurasi untuk menangani unggahan server langsung.
accept: Menentukan serangkaian format gambar yang diperbolehkan (misalnya, 'webp', 'avif')uploadUrl: Tentukan titik akhir backend tempatFileobjek akan dikirim melaluiPOSTparams: Objek opsional untuk mengirim data tambahan (seperti token CSRF, ID pengguna, atau nama folder) bersama file gambar
Contoh penggunaan (Konfigurasi Lengkap)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | const options = { placeholder: 'Start writing...', toolbar: [ 'link', { image: { fileInput: { accept: ['webp', 'avif'], // restrict the image upload format uploadUrl: '/api/upload', // Your upload endpoint params: { _token: 'your_csrf_token_here', // Essential for Laravel/Django folder: 'blog_posts' } }, // Supports boolean: true/false OR object: { required: true } altInput: { required: true } } }, 'preview' ], } const editor = new MarkdownEditor('#markdown-editor', options); |
📡 Integrasi Server
Permintaan
Redaksi mengirimkan a POST permintaan sebagai multipart/form-data. Secara default, ini mencakup:
image_file: Objek file sebenarnyaimage_alt: Teks alternatif yang dimasukkan oleh pengguna- ...ditambah data khusus apa pun yang ditentukan di
paramsobyek
Respon yang Diperlukan
Untuk mengonfirmasi keberhasilan upload dan memasukkan gambar ke editor, server Anda harus mengembalikan struktur JSON berikut:
1 2 3 4 | { "success": true, "image_path": "https://cdn.yourdomain.com/uploads/image.webp" } |
Catatan: Pastikan Anda menggunakan kuncinya image_path untuk URL gambar yang diunggah.
Validasi Teks Alt Gambar (altInput)
Untuk memastikan konten Anda tetap dapat diakses dan ramah SEO, MarkdownEditor menerapkan validasi teks alternatif secara default.
- Perilaku Default: Jika
altInputtidak ditentukan, defaultnya adalah{ required: true } - Menerapkan Aksesibilitas: Pengguna akan dilarang memasukkan gambar sampai deskripsi alternatif diberikan
1. Default (Tidak diperlukan konfigurasi)
1 2 3 4 | // Alt text is REQUIRED by default image: { fileInput: { uploadUrl: '/api/upload' } } |
2. Singkatan (Nonaktifkan Validasi)
Jika Anda ingin mengizinkan gambar tanpa deskripsi, cukup setel boolean ke false.
1 2 3 | image: { altInput: false // Users can now skip the alt text field } |
3. Berbasis objek (Eksplisit)
1 2 3 4 5 | image: { altInput: { required: false // Disables alt text validation — users can skip the alt field } } |
Penggunaan Gambar Standar (No fileInput)
Jika fileInput tidak dikonfigurasi, editor defaultnya menggunakan modal sederhana berbasis URL. Ini ideal jika sebagian besar pengguna Anda terhubung ke host gambar eksternal.
1 2 3 4 5 6 7 8 | const options = { toolbar: [ 'link', 'image', 'preview' ], } const editor = new MarkdownEditor('#markdown-editor', options); |
💡 Mengapa menggunakan params?
Dalam kerangka kerja seperti Laravel atau Django, Anda tidak dapat mengunggah berkas tanpa token CSRF. Dengan menambahkan _token ke params keberatan, permintaan Anda akan melewati middleware keamanan backend dengan mulus, mempertahankan filosofi "Logika Nol" untuk pengontrol sisi server Anda.
⌨️ Pintasan Papan Ketik
Tindakan pemformatan umum dapat dipicu langsung dari keyboard tanpa menyentuh toolbar. Setiap pintasan juga ditampilkan di tooltip tombol toolbar yang sesuai.
| Jalan pintas | Tindakan |
|---|---|
Ctrl + B / ⌘ B | Alihkan Tebal |
Ctrl + I / ⌘ I | Alihkan Miring |
Ctrl + K / ⌘ K | Sisipkan Tautan |
Ctrl + ` / ⌘ ` | Beralih sebaris Code |
Ctrl + Shift + S / ⌘ ⇧ S | Alihkan |
Ctrl + 1 / ⌘ 1 | Judul 1 |
Ctrl + 2 / ⌘ 2 | Judul 2 |
Ctrl + 3 / ⌘ 3 | Pos 3 |
Ctrl + L / ⌘ L | Alihkan daftar poin |
Ctrl + Z / ⌘ Z | Membuka |
Ctrl + Shift + Z / ⌘ ⇧ Z | Mengulangi |
Tab | Indentasi baris yang dipilih |
Shift + Tab | Garis yang dipilih keluar |
Ctrl + F / ⌘ F | Buka panel Temukan |
Ctrl + H / ⌘ H | Buka panel Temukan & Ganti |
Ctrl + Shift + F / ⌘ ⇧ F | Alihkan pratinjau layar penuh |
F11 | Alihkan pratinjau layar penuh |
Escape | Tutup panel Temukan / Keluar dari pratinjau layar penuh |
🔍 Temukan & Ganti
Panel temukan dan ganti bawaan tersedia di dalam editor: tidak diperlukan ekstensi browser atau alat terpisah.
- Tekan
Ctrl + F(atau⌘ F) untuk membuka panel Temukan - Tekan
Ctrl + H(atau⌘ H) untuk membuka panel Temukan & Ganti - Penelusuran tidak peka huruf besar-kecil dan menampilkan penghitung pertandingan langsung (misalnya 3 dari 12)
- Navigasi pertandingan dengan tombol ▲ / ▼ atau
Enter/Shift + Enter - Ganti menggantikan kecocokan yang disorot saat ini; Ganti Semua menggantikan setiap kejadian sekaligus
- Tekan
Escapeuntuk menutup panel dan mengembalikan fokus ke editor
Panel mengapung di sudut kanan atas area konten editor dan tidak mengganggu penulisan.
🔗 Tautan dari URL yang ditempel
Pilih beberapa teks, tempelkan URL di atasnya, dan Anda mendapatkan tautan penurunan harga alih-alih URL yang menggantikan apa yang Anda pilih.
1 2 | Read the docs <- select "the docs", paste https://example.com Read [the docs](https://example.com) <- what you get |
Aturannya sengaja dibuat ketat: hanya telanjang http atau https URL tanpa spasi diperlakukan dengan cara ini. Menempelkan kalimat yang kebetulan berisi URL, atau menempelkan tanpa memilih apa pun, berperilaku seperti tempel biasa.
Fitur
🔌 Integrasi Formulir Asli
Bekerja persis seperti standar <textarea>. Tidak ada API yang rumit: cukup gunakan value atau name atribut. Ini "hanya berfungsi" dengan pengiriman formulir HTML standar di PHP, Django, atau Node.js.
🖼️ Unggah Gambar Tingkat Lanjut
Konfigurasikan unggahan server asli melalui API. Hindari string Base64 yang berat untuk memastikan pemuatan halaman lebih cepat dan SEO unggul dengan menghosting gambar di CDN Anda sendiri.
🔀 Mode Hibrid & Biasa
Beralih antara a Hibrida (WYSIWYG) pengalaman untuk mengedit visual atau Penurunan Harga Biasa mode untuk nuansa pengkodean tradisional.
🚀 Performa Tinggi
A 53 KB di-gzip bundel (252 KB diperkecil, termasuk CSS) dioptimalkan untuk "Konten Berat". Menangani dokumen berukuran besar dan file besar tanpa jeda input atau penurunan kinerja. Pembaruan pratinjau yang dibatalkan, perhitungan gaya yang di-cache, dan penanganan keyboard bebas konflik: jadi Tab dan Enter selalu melakukan satu hal.
🌍 Dukungan RTL bawaan
Dukungan asli untuk bahasa Kanan-Kiri seperti Arab, Urdu, dan Farsi. Sempurna untuk membangun aplikasi yang dapat diakses secara global.
✨ Penyorotan Sintaks
Peningkatan keterbacaan dengan kode yang jelas dan format penurunan harga.
🌙 Tema Adaptif
Termasuk dukungan Mode Gelap otomatis. Ini disinkronkan dengan pengaturan sistem Anda atau Frutjam UI perpustakaan untuk pengalaman visual yang mulus.
📝 Pengeditan Cerdas
Kelanjutan daftar otomatis gaya GitHub untuk daftar terurut, daftar tidak berurutan, dan daftar periksa: tekan Enter dan editor melanjutkan polanya. Kotak centang di panel pratinjau dapat diklik dan langsung disinkronkan kembali ke sumber penurunan harga.
📱 Sepenuhnya Responsif
UI yang lancar dan mengutamakan seluler yang beradaptasi sempurna dengan desktop, tablet, dan ponsel cerdas untuk mengedit saat bepergian.
📦 Dukungan Universal
Kompatibel dengan ESM, UMD, CommonJS, dan IIFE. Bekerja di luar kotak melalui CDN (<script src>), npm, atau bundler apa pun (Vite, webpack, Rollup): tidak diperlukan konfigurasi tambahan.
♿ Dapat Diakses secara Default
Dukungan penuh ARIA bawaan: landmark toolbar, wilayah pratinjau berlabel, tombol ramah pembaca layar, aria-pressed pada tombol pratinjau, disabled Dan aria-disabled pada alat yang tidak aktif, dan memperbaiki pemulihan fokus saat modals ditutup.
🛡️ Nol Konflik CSS
Gaya editor sepenuhnya tercakup .markdown-editor-wrapper. Preflight global Tailwind dikecualikan sehingga editor dapat bekerja dengan aman bersama Bootstrap, Tailwind, atau kerangka kerja lainnya tanpa merusak gayanya.
⌨️ Pintasan Papan Ketik
Ctrl+B, Ctrl+I, Ctrl+K, Ctrl+`, Ctrl+Shift+S: tindakan pemformatan umum tanpa menyentuh mouse. Setiap pintasan ditampilkan di tooltip tombol toolbar.
🔍 Temukan & Ganti
Tekan Ctrl+F untuk menemukan atau Ctrl+H untuk membuka temukan & ganti. Pencarian tidak peka huruf besar-kecil dengan penghitung pencocokan langsung, navigasi berikutnya/sebelumnya, penggantian tunggal, dan penggantian semua: tanpa meninggalkan editor.
🔒 Pratinjau Aman XSS
Pratinjau yang diberikan dibersihkan melalui DOMPurifikasi sebelum ditulis ke DOM. Tag skrip, pengendali kejadian sebaris, dan URL berbahaya dalam masukan penurunan harga yang dibuat akan dihapus secara otomatis: tidak diperlukan konfigurasi.
▶️ Pratinjau Waktu Nyata
Lihat penurunan harga Anda ditampilkan secara instan saat Anda mengetik.
🔗 Integrasi Mudah
Integrasikan secara mulus ke dalam proyek web apa pun dengan pengaturan minimal.
🛠️ Bilah Alat yang Dapat Disesuaikan
Konfigurasikan dan susun ulang opsi toolbar secara dinamis seperti huruf tebal, miring, dan lainnya.
Contoh Konfigurasi Lengkap
Gunakan contoh komprehensif ini untuk menginisialisasi MarkdownEditor dengan semua fitur utama, termasuk pengurutan toolbar khusus dan penanganan upload gambar tingkat lanjut.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | const editor = new MarkdownEditor('#markdown-editor', { mode: 'hybrid', placeholder: 'Start writing...', footer: { line: true, col: true, chars: true, words: true, }, onChange(value) { console.log('Content updated:', value.length, 'characters'); }, labels: { 'Bold': 'Gras', 'Italic': 'Italique', 'Uploading...': 'Téléversement...', }, toolbar: [ 'heading', 'bold', 'italic', 'strikethrough', 'blockquote', 'ul', 'ol', 'checklist', 'code', 'codeblock', 'hr', 'table', { image: { fileInput: { accept: ['webp', 'avif', 'png'], uploadUrl: '/api/upload' } } }, 'link', 'undo', 'redo', 'indent', 'outdent', 'preview' ], }); // Read content natively const markdown = document.getElementById('markdown-editor').value; // destroy() when the view unmounts (SPAs) // editor.destroy(); |
Apakah ini berguna?
Bintang GitHub membantu pengembang lain menemukan editornya. Itu bagian dari buah-buahan. Sebuah bintang di sana juga membantu.