Bagaimana aplikasi web mendeteksi acara tempel dan mengambil data yang akan ditempelkan?
Saya ingin menghapus konten HTML sebelum teks disisipkan ke editor teks kaya.
Membersihkan teks setelah disisipkan sesudahnya berfungsi, tetapi masalahnya adalah bahwa semua pemformatan sebelumnya hilang. Misalnya, saya bisa menulis kalimat di editor dan membuatnya tebal, tetapi ketika saya menempelkan teks baru, semua pemformatan hilang. Saya ingin membersihkan hanya teks yang disisipkan, dan membiarkan format sebelumnya tidak tersentuh.
Idealnya, solusinya harus bekerja di semua browser modern (misalnya, MSIE, Gecko, Chrome, dan Safari).
Perhatikan bahwa MSIE memiliki clipboardData.getData()
, tetapi saya tidak dapat menemukan fungsionalitas yang serupa untuk browser lain.
event.clipboardData.getData('Text')
bekerja untuk saya.document.addEventListener('paste'...
bekerja untuk saya tetapi menyebabkan konflik jika pengguna ingin dapat menempel di tempat lain pada halaman. Kemudian saya mencobamyCanvasElement.addEventListener('paste'...
, tetapi itu tidak berhasil. Akhirnya saya tahumyCanvasElement.parentElement.addEventListener('paste'...
berhasil.Jawaban:
Situasi telah berubah sejak menulis jawaban ini: sekarang Firefox telah menambahkan dukungan di versi 22, semua browser utama sekarang mendukung mengakses data clipboard dalam acara tempel. Lihat jawaban Nico Burns sebagai contoh.
Di masa lalu ini umumnya tidak mungkin dilakukan dengan cara lintas-browser. Yang ideal adalah untuk bisa mendapatkan konten yang disisipkan melalui
paste
acara, yang dimungkinkan di browser terbaru tetapi tidak di beberapa browser lama (khususnya, Firefox <22).Ketika Anda perlu mendukung browser lama, apa yang dapat Anda lakukan cukup terlibat dan sedikit peretasan yang akan bekerja di Firefox 2+, IE 5.5+ dan browser WebKit seperti Safari atau Chrome. Versi terbaru dari TinyMCE dan CKEditor menggunakan teknik ini:
designMode
dan panggilfocus()
textarea, sehingga menggerakkan tanda sisipan dan secara efektif mengarahkan ulang pastadesignMode
kembali, mengembalikan pilihan pengguna dan menempelkan teks masuk.Perhatikan bahwa ini hanya akan berfungsi untuk acara tempel keyboard dan bukan pasta dari konteks atau edit menu. Pada saat acara paste diaktifkan, sudah terlambat untuk mengarahkan ulang tanda sisipan ke dalam textarea (setidaknya di beberapa browser, setidaknya).
Jika Anda perlu mendukung Firefox 2, perhatikan bahwa Anda harus meletakkan textarea di dokumen induk daripada dokumen iframe editor WYSIWYG di peramban itu.
sumber
designMode
adalah properti Boolean daridocument
dan membuat seluruh halaman dapat diedit kapantrue
. Editor WYSIWYG biasanya menggunakan iframe dengandesignMode
on sebagai panel yang dapat diedit. Menyimpan dan memulihkan pilihan pengguna dilakukan dengan satu cara di IE dan lainnya di browser lain, seperti menempelkan konten ke editor. Anda harus mendapatkanTextRange
di IE danRange
browser lainnya.paste
acara tersebut tetapi umumnya sudah terlambat untuk mengarahkan ulang pasta ke elemen lain, sehingga peretasan ini tidak akan berfungsi. Fallback di sebagian besar editor adalah untuk menunjukkan dialog bagi pengguna untuk menempel.paste
acara tersebut, namun Firefox akan memungkinkan Anda untuk menghapus konten elemen (dan menyimpannya ke variabel sehingga Anda dapat mengembalikannya nanti). Jika kontainer ini adalahdiv
(mungkin berfungsiiframe
juga) maka Anda dapat menggilir konten yang ditempel menggunakan metode dom normal, atau mendapatkannya sebagai string menggunakaninnerHTML
. Anda kemudian dapat mengembalikan konten sebelumnyadiv
, dan menyisipkan konten apa pun yang Anda suka. Oh, dan Anda harus menggunakan timer hack yang sama seperti di atas. Saya terkejut TinyMCE tidak melakukan ini ...Solusi # 1 (Khusus Teks Biasa dan membutuhkan Firefox 22+)
Bekerja untuk IE6 +, FF 22+, Chrome, Safari, Edge (Hanya diuji di IE9 +, tetapi seharusnya berfungsi untuk versi yang lebih rendah)
Jika Anda memerlukan dukungan untuk menempelkan HTML atau Firefox <= 22, lihat Solusi # 2.
HTML
JavaScript
JSFiddle: https://jsfiddle.net/swL8ftLs/12/
Perhatikan bahwa solusi ini menggunakan parameter 'Teks' untuk
getData
fungsi, yang tidak standar. Namun, ini berfungsi di semua browser pada saat penulisan.Solusi # 2 (HTML dan berfungsi untuk Firefox <= 22)
Diuji dalam IE6 +, FF 3.5+, Chrome, Safari, Edge
HTML
JavaScript
JSFiddle: https://jsfiddle.net/nicoburns/wrqmuabo/23/
Penjelasan
The
onpaste
event daridiv
memilikihandlePaste
fungsi yang melekat padanya dan melewati argumen tunggal:event
objek untuk acara paste. Yang menarik bagi kami adalahclipboardData
properti acara ini yang memungkinkan akses clipboard di browser non-ie. Di IE, yang setara adalahwindow.clipboardData
, meskipun ini memiliki API yang sedikit berbeda.Lihat bagian sumber daya di bawah ini.
The
handlepaste
Fungsi:Fungsi ini memiliki dua cabang.
Pemeriksaan pertama untuk keberadaan
event.clipboardData
dan memeriksa apakahtypes
properti itu mengandung 'teks / html' (types
bisa berupaDOMStringList
yang diperiksa menggunakancontains
metode, atau string yang diperiksa menggunakanindexOf
metode). Jika semua kondisi ini terpenuhi, maka kami melanjutkan seperti dalam solusi # 1, kecuali dengan 'teks / html' alih-alih 'teks / polos'. Ini saat ini berfungsi di Chrome dan Firefox 22+.Jika metode ini tidak didukung (semua browser lain), maka kami
DocumentFragment
waitForPastedData
fungsinyaThe
waitforpastedata
Fungsi:Fungsi ini pertama-tama memberikan jajak pendapat untuk data yang di-paste (sekali per 20 ms), yang diperlukan karena tidak langsung muncul. Ketika data telah muncul itu:
Itu
processpaste
Fungsi:Apakah hal-hal yang sewenang-wenang dengan data yang di-paste. Dalam hal ini kami hanya memberitahukan data, Anda dapat melakukan apa pun yang Anda suka. Anda mungkin ingin menjalankan data yang di-paste melalui semacam proses sanitasi data.
Menyimpan dan mengembalikan posisi kursor
Dalam situasi nyata Anda mungkin ingin menyimpan pilihan sebelumnya, dan mengembalikannya setelah itu ( Tetapkan posisi kursor pada contentEditable <div> ). Anda kemudian bisa menyisipkan data yang di-paste di posisi kursor ketika pengguna memulai tindakan tempel.
Sumber:
Terima kasih kepada Tim Down untuk menyarankan penggunaan DocumentFragment, dan abligh untuk menangkap kesalahan di Firefox karena penggunaan DOMStringList bukan string untuk clipboardData.types
sumber
DocumentFragment
daripada menggunakaninnerHTML
karena beberapa alasan: pertama, Anda menyimpan penangan acara yang ada; kedua, menyimpan dan memulihkaninnerHTML
tidak dijamin untuk membuat salinan DOM sebelumnya yang identik; ketiga, Anda kemudian dapat menyimpan pilihan sebagaiRange
daripada harus mencari-cari dengan menambahkan elemen marker atau menghitung offset teks (yang harus Anda lakukan jika menggunakaninnerHTML
).DocumentFragment
pada IE? Ini sama dengan di browser lain, kecuali jika Anda menggunakan Range danextractContents()
melakukannya, yang tidak lebih ringkas daripada alternatif dalam hal apa pun. Saya telah menerapkan contoh teknik Anda, menggunakan Rangy untuk menjaga hal-hal bagus dan seragam di seluruh browser: jsfiddle.net/bQeWC/4 .waitforpastedata
fungsitext/html
menggunakan W3C Clipboard API. Di masa lalu upaya seperti itu akan menimbulkan pengecualian. Jadi orang tidak lagi membutuhkan solusi / peretasan ini untuk Edge.Versi sederhana:
Menggunakan
clipboardData
Demo: http://jsbin.com/nozifexasu/edit?js,output
Edge, Firefox, Chrome, Safari, Opera diuji.
⚠ Document.execCommand () sudah usang sekarang.
Catatan: Ingatlah untuk memeriksa juga input / output di sisi server (seperti tag-strip PHP )
sumber
window.clipboardData.getData('Text');
e.preventDefault(); if (e.clipboardData) { content = (e.originalEvent || e).clipboardData.getData('text/plain'); document.execCommand('insertText', false, content); } else if (window.clipboardData) { content = window.clipboardData.getData('Text'); document.selection.createRange().pasteHTML(content); }
Demo Langsung
Diuji pada Chrome / FF / IE11
Ada gangguan Chrome / IE yang mana browser ini menambahkan
<div>
elemen untuk setiap baris baru. Ada posting tentang ini di sini dan itu bisa diperbaiki dengan mengatur elemen contenteditable menjadidisplay:inline-block
Pilih beberapa HTML yang disorot dan rekatkan di sini:
sumber
Saya telah menulis sedikit bukti konsep untuk proposal Tim Downs di sini dengan textarea di luar layar. Dan begini kodenya:
Cukup salin dan tempel seluruh kode ke dalam satu file html dan coba tempel (menggunakan ctrl-v) teks dari clipboard di mana saja pada dokumen.
Saya sudah mengujinya di IE9 dan versi baru Firefox, Chrome dan Opera. Bekerja dengan cukup baik. Juga baik bahwa seseorang dapat menggunakan kombinasi tombol apa pun yang ia sukai untuk melakukan triger fungsi ini. Tentu saja jangan lupa untuk menyertakan sumber jQuery.
Jangan ragu untuk menggunakan kode ini dan jika Anda datang dengan beberapa perbaikan atau masalah, silakan kirim kembali. Perhatikan juga bahwa saya bukan pengembang Javascript sehingga saya mungkin melewatkan sesuatu (=> lakukan testign Anda sendiri).
sumber
Berdasarkan l2aelba anwser. Ini diuji pada FF, Safari, Chrome, IE (8,9,10 dan 11)
sumber
Yang ini tidak menggunakan setTimeout ().
Saya telah menggunakan ini artikel bagus untuk mencapai dukungan lintas browser.
Kode ini diperpanjang dengan pegangan seleksi sebelum menempel: demo
sumber
Untuk membersihkan teks yang disisipkan dan mengganti teks yang saat ini dipilih dengan teks yang disisipkan masalah cukup sepele:
JS:
sumber
Ini harus bekerja pada semua browser yang mendukung acara onpaste dan pengamat mutasi.
Solusi ini lebih dari sekadar mendapatkan teks saja, ini sebenarnya memungkinkan Anda untuk mengedit konten yang ditempelkan sebelum disisipkan ke dalam elemen.
Ia bekerja dengan menggunakan event onpaste yang dapat diedit (didukung oleh semua browser utama) pengamat mutasi (didukung oleh Chrome, Firefox dan IE11 +)
Langkah 1
Buat elemen HTML dengan contenteditable
Langkah 2
Dalam kode Javascript Anda, tambahkan acara berikut
Kita perlu mengikat pasteCallBack, karena pengamat mutasi akan dipanggil secara tidak sinkron.
langkah 3
Tambahkan fungsi berikut ke kode Anda
Apa yang dilakukan kode:
Contoh
Tampilkan cuplikan kode
Terima kasih banyak kepada Tim Down. Lihat posting ini untuk jawabannya:
Dapatkan konten yang disisipkan pada dokumen pada acara tempel
sumber
Solusi yang berfungsi bagi saya adalah menambahkan pendengar acara untuk menempelkan acara jika Anda menempelkan ke input teks. Karena peristiwa tempel terjadi sebelum teks dalam perubahan input, di dalam handler di tempel saya membuat fungsi yang ditangguhkan di dalamnya saya memeriksa perubahan di kotak input saya yang terjadi pada tempel:
sumber
Ini terlalu lama untuk mengomentari jawaban Nico, yang menurut saya tidak berfungsi lagi di Firefox (per komentar), dan tidak berfungsi untuk saya di Safari seperti sebelumnya.
Pertama, sekarang Anda tampaknya dapat membaca langsung dari clipboard. Daripada kode seperti:
menggunakan:
karena Firefox memiliki
types
bidang yangDOMStringList
tidak diimplementasikantest
.Firefox berikutnya tidak akan mengizinkan tempel kecuali fokusnya ada di
contenteditable=true
bidang.Akhirnya, Firefox tidak akan mengizinkan tempel dengan andal kecuali fokusnya ada pada
textarea
(atau mungkin input) yang tidak hanyacontenteditable=true
tetapi juga:display:none
visibility:hidden
Saya mencoba untuk menyembunyikan bidang teks sehingga saya dapat membuat karya pasta melalui emulator JS VNC (yaitu akan pergi ke klien jarak jauh dan tidak ada sebenarnya
textarea
dll untuk menempel ke). Saya menemukan mencoba menyembunyikan bidang teks di atas memberikan gejala di mana kadang-kadang bekerja, tetapi biasanya gagal pada tempel kedua (atau ketika bidang itu dihapus untuk mencegah menempelkan data yang sama dua kali) karena bidang kehilangan fokus dan tidak akan mendapatkan kembali dengan benar meskipun begitufocus()
. Solusi yang saya temukan adalah menaruhnyaz-order: -1000
, membuatnyadisplay:none
, menjadikannya sebagai 1px demi 1px, dan mengatur semua warna menjadi transparan. Yuck.Di Safari, Anda bagian kedua dari yang di atas berlaku, yaitu Anda harus memiliki
textarea
yang tidakdisplay:none
.sumber
Pertama yang terlintas dalam pikiran adalah pastehandler lib penutupan google http://closure-library.googlecode.com/svn/trunk/closure/goog/demos/pastehandler.html
sumber
Solusi sederhana:
sumber
Ini bekerja untuk saya:
sumber
sumber
Anda dapat melakukan ini dengan cara ini:
gunakan plugin jQuery ini untuk acara pra & pasca tempel:
Sekarang Anda dapat menggunakan plugin ini ;:
Penjelasan
Pertama-tama set uid untuk semua elemen yang ada sebagai atribut data.
Kemudian bandingkan semua node POST PASTE event. Jadi dengan membandingkan Anda dapat mengidentifikasi yang baru dimasukkan karena mereka akan memiliki uid, lalu hapus atribut style / class / id dari elemen yang baru dibuat, sehingga Anda dapat mempertahankan pemformatan yang lebih lama.
sumber
sumber
Biarkan peramban menempel seperti biasa di div kontennya yang dapat diedit dan kemudian setelah tempel menukar elemen rentang yang digunakan untuk gaya teks khusus dengan teks itu sendiri. Ini sepertinya berfungsi baik di internet explorer dan browser lain yang saya coba ...
Solusi ini mengasumsikan bahwa Anda menjalankan jQuery dan bahwa Anda tidak ingin pemformatan teks di salah satu div yang dapat diedit konten Anda .
Sisi positifnya adalah sangat sederhana.
sumber
span
memberi tag? Saya akan membayangkan pertanyaannya adalah tentang semua tag.Solusi ini menggantikan tag html, sederhana dan lintas-browser; periksa jsfiddle ini: http://jsfiddle.net/tomwan/cbp1u2cx/1/ , kode inti:
perhatikan: Anda harus melakukan beberapa pekerjaan tentang filter xss di sisi belakang karena solusi ini tidak dapat menyaring string seperti '<< >>'
sumber
Ini adalah kode yang ada diposting di atas tetapi saya telah memperbaruinya untuk IE, bugnya adalah ketika teks yang ada dipilih dan disisipkan tidak akan menghapus konten yang dipilih. Ini telah diperbaiki oleh kode di bawah ini
Lihat kode lengkap di bawah ini
sumber