W jaki sposób aplikacja internetowa może wykryć zdarzenie wklejania i pobrać dane do wklejenia?
Chciałbym usunąć treść HTML przed wklejeniem tekstu do edytora tekstu sformatowanego.
Czyszczenie tekstu po wklejeniu później działa, ale problem polega na tym, że całe poprzednie formatowanie zostało utracone. Na przykład mogę napisać zdanie w edytorze i pogrubić je, ale po wklejeniu nowego tekstu całe formatowanie zostanie utracone. Chcę wyczyścić tylko wklejony tekst i pozostawić poprzednie formatowanie nietknięte.
Idealnie rozwiązanie powinno działać we wszystkich nowoczesnych przeglądarkach (np. MSIE, Gecko, Chrome i Safari).
Zauważ, że MSIE ma clipboardData.getData()
, ale nie mogłem znaleźć podobnej funkcjonalności dla innych przeglądarek.
event.clipboardData.getData('Text')
pracował dla mnie.document.addEventListener('paste'...
działało dla mnie, ale powodowało konflikty, jeśli użytkownik chciał mieć możliwość wklejenia w innym miejscu strony. Potem próbowałemmyCanvasElement.addEventListener('paste'...
, ale to nie działało. W końcu doszedłem do wniosku, żemyCanvasElement.parentElement.addEventListener('paste'...
działa.Odpowiedzi:
Sytuacja zmieniła się od czasu napisania tej odpowiedzi: teraz, gdy Firefox dodał obsługę w wersji 22, wszystkie główne przeglądarki obsługują teraz dostęp do danych schowka w przypadku wklejania. Zobacz przykład Nico Burnsa .
W przeszłości nie było to na ogół możliwe w przeglądarce. Idealnym rozwiązaniem byłoby uzyskanie wklejonej zawartości za pośrednictwem
paste
zdarzenia, co jest możliwe w najnowszych przeglądarkach, ale nie w niektórych starszych przeglądarkach (w szczególności Firefox <22).Kiedy potrzebujesz obsługi starszych przeglądarek, możesz zaangażować się i trochę włamać się do przeglądarki Firefox 2+, IE 5.5+ i przeglądarek WebKit, takich jak Safari lub Chrome. Najnowsze wersje TinyMCE i CKEditor używają tej techniki:
designMode
wyłącz i włączfocus()
obszar tekstowy, przesuwając kursor i skutecznie przekierowując pastędesignMode
pola tekstowego , usuwa obszar tekstowy z dokumentu, włącza się ponownie, przywraca wybór użytkownika i wkleja tekst.Pamiętaj, że będzie to działać tylko w przypadku zdarzeń wklejania klawiatury, a nie wkleja się z menu kontekstowego lub edycji. Do czasu uruchomienia zdarzenia wklejania jest już za późno, aby przekierować kursor do obszaru tekstowego (przynajmniej w niektórych przeglądarkach).
W mało prawdopodobnym przypadku, gdy potrzebujesz obsługi Firefox 2, pamiętaj, że musisz umieścić obszar tekstowy w dokumencie nadrzędnym zamiast dokumentu iframe edytora WYSIWYG w tej przeglądarce.
źródło
designMode
jest to właściwość logicznadocument
i umożliwia edycję całej strony, gdytrue
. Edytory WYSIWYG zwykle używają ramki iframe zdesignMode
włączonym jako okienko do edycji. Zapisywanie i przywracanie wyboru użytkownika odbywa się w IE, a innym w innych przeglądarkach, podobnie jak wklejanie zawartości do edytora. Musisz uzyskaćTextRange
w IE iRange
innych przeglądarkach.paste
zdarzenia, ale na ogół jest już za późno, aby przekierować wklej do innego elementu, więc ten hack nie zadziała. W większości edytorów awarią jest wyświetlenie okna dialogowego, w którym użytkownik może wkleić.paste
wydarzeniu, ale pozwoli ci wyczyścić zawartość tego elementu (i zapisać go w zmiennej, abyś mógł później ją przywrócić). Jeśli ten kontener jestdiv
(prawdopodobnie też działaiframe
), możesz następnie przechodzić między wklejonymi treściami przy użyciu normalnych metod dom lub uzyskać jako ciąg znaków przy użyciuinnerHTML
. Następnie możesz przywrócić poprzednią zawartośćdiv
i wstawić dowolną treść. Aha, i musisz użyć tego samego hacka z timerem jak powyżej. Dziwi mnie, że TinyMCE tego nie robi ...Rozwiązanie nr 1 (tylko zwykły tekst i wymaga przeglądarki Firefox 22+)
Działa dla IE6 +, FF 22+, Chrome, Safari, Edge (testowany tylko w IE9 +, ale powinien działać dla niższych wersji)
Jeśli potrzebujesz pomocy przy wklejaniu HTML lub Firefox <= 22, zobacz Rozwiązanie nr 2.
HTML
JavaScript
JSFiddle: https://jsfiddle.net/swL8ftLs/12/
Zauważ, że w tym rozwiązaniu użyto parametru „Tekst” dla
getData
funkcji, co jest niestandardowe. Działa jednak we wszystkich przeglądarkach w momencie pisania.Rozwiązanie nr 2 (HTML i działa w przeglądarce Firefox <= 22)
Testowane w IE6 +, FF 3.5+, Chrome, Safari, Edge
HTML
JavaScript
JSFiddle: https://jsfiddle.net/nicoburns/wrqmuabo/23/
Wyjaśnienie
onpaste
Wydarzeniediv
mahandlePaste
funkcję dołączony do niej i podał jeden argument:event
obiekt dla zdarzenia wklejania. Szczególnie interesuje nasclipboardData
właściwość tego wydarzenia, która umożliwia dostęp do schowka w innych przeglądarkach. W IE odpowiednikiem jestwindow.clipboardData
, choć ma nieco inny interfejs API.Zobacz sekcję zasobów poniżej.
handlepaste
Funkcja:Ta funkcja ma dwie gałęzie.
Pierwsze sprawdzenie istnienia
event.clipboardData
i sprawdzenie, czy jegotypes
właściwość zawiera „text / html” (types
może to być alboDOMStringList
sprawdzany za pomocącontains
metody, albo ciąg sprawdzany za pomocąindexOf
metody). Jeśli wszystkie te warunki są spełnione, postępujemy jak w rozwiązaniu nr 1, z wyjątkiem „text / html” zamiast „text / plain”. Obecnie działa to w Chrome i Firefox 22+.Jeśli ta metoda nie jest obsługiwana (wszystkie inne przeglądarki), to my
DocumentFragment
waitForPastedData
funkcjęwaitforpastedata
Funkcja:Ta funkcja najpierw sonduje wklejone dane (raz na 20 ms), co jest konieczne, ponieważ nie pojawia się od razu. Gdy pojawią się dane:
processpaste
Funkcja:Wykonuje dowolne czynności z wklejonymi danymi. W takim przypadku po prostu ostrzegamy dane, możesz zrobić, co chcesz. Prawdopodobnie będziesz chciał uruchomić wklejone dane w procesie dezynfekcji danych.
Zapisywanie i przywracanie pozycji kursora
W prawdziwej sytuacji prawdopodobnie zechcesz wcześniej zapisać wybór i przywrócić go później ( Ustaw pozycję kursora na contentEditable <div> ). Następnie można wstawić wklejone dane w miejscu, w którym znajdował się kursor, gdy użytkownik zainicjował akcję wklejania.
Zasoby:
Dziękujemy Timowi Downowi za zasugerowanie użycia DocumentFragment i dziękuję za złapanie błędu w Firefoksie z powodu użycia DOMStringList zamiast ciągu dla clipboardData.types
źródło
DocumentFragment
niż używaćinnerHTML
z kilku powodów: po pierwsze, zachowujesz istniejące programy obsługi zdarzeń; po drugie,innerHTML
nie można zagwarantować , że zapisanie i przywrócenie spowoduje utworzenie identycznej kopii poprzedniego DOM; po trzecie, możesz następnie zapisać zaznaczenie jako opcjęRange
zamiast marnować czas na dodawanie elementów znaczników lub obliczanie przesunięć tekstu (co musisz zrobić, jeśli użyjeszinnerHTML
).DocumentFragment
jest uciążliwa w IE? Jest to to samo, co w innych przeglądarkach, chyba że użyjesz Range iextractContents()
zrobisz to, co w żadnym wypadku nie jest bardziej zwięzłe niż alternatywa. Wdrożyłem przykład Twojej techniki, używając Rangy, aby zachować ładność i jednolitość w różnych przeglądarkach: jsfiddle.net/bQeWC/4 .waitforpastedata
funkcjitext/html
za pomocą W3C Clipboard API. W przeszłości taka próba rzucałaby wyjątek. Więc nie trzeba już tego obejścia / hakowania dla Edge.Prosta wersja:
Za pomocą
clipboardData
Próbny : http://jsbin.com/nozifexasu/edit?js,output
Testowane Edge, Firefox, Chrome, Safari, Opera.
⚠ Document.execCommand () jest już nieaktualny .
Uwaga: pamiętaj, aby sprawdzać także wejścia / wyjścia po stronie serwera (takie jak PHP strip-tags )
źródło
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 na żywo
Testowane na Chrome / FF / IE11
Denerwuje Chrome / IE, ponieważ przeglądarki te dodają
<div>
element dla każdej nowej linii. Jest tutaj post na ten temat , który można naprawić, ustawiając contentediable element nadisplay:inline-block
Wybierz podświetlony kod HTML i wklej go tutaj:
źródło
Napisałem tutaj mały dowód koncepcji propozycji Tima Downsa z obszarem tekstowym poza ekranem. A oto kod:
Po prostu skopiuj i wklej cały kod do jednego pliku HTML i spróbuj wkleić (używając ctrl-v) tekst ze schowka w dowolnym miejscu dokumentu.
Przetestowałem to w IE9 i nowych wersjach Firefox, Chrome i Opera. Działa całkiem dobrze. Dobrze też, że można użyć dowolnej kombinacji klawiszy, którą preferuje, aby uruchomić tę funkcję. Oczywiście nie zapomnij podać źródeł jQuery.
Zachęcamy do korzystania z tego kodu, a jeśli pojawią się jakieś poprawki lub problemy, prosimy o przesłanie ich z powrotem. Zauważ też, że nie jestem programistą Javascript, więc mogłem coś przeoczyć (=> zrób swój własny testign).
źródło
Oparty na l2aelba anwser . Zostało to przetestowane na FF, Safari, Chrome, IE (8,9,10 i 11)
źródło
Ten nie używa żadnej metody setTimeout ().
Użyłem tego świetnego artykułu, aby uzyskać wsparcie dla różnych przeglądarek.
Ten kod jest rozszerzony o uchwyt wyboru przed wklejeniem: demo
źródło
W przypadku czyszczenia wklejonego tekstu i zastępowania aktualnie zaznaczonego tekstu wklejonym tekstem sprawa jest dość trywialna:
JS:
źródło
Powinno to działać we wszystkich przeglądarkach obsługujących zdarzenie onpaste i obserwatora mutacji.
To rozwiązanie wykracza poza uzyskiwanie samego tekstu, pozwala na edycję wklejonej zawartości przed wklejeniem do elementu.
Działa przy użyciu edytowalnego zdarzenia onpaste (obsługiwanego przez wszystkie główne przeglądarki) i obserwatora mutacji (obsługiwanego przez Chrome, Firefox i IE11 +)
krok 1
Utwórz element HTML z treścią
krok 2
W kodzie JavaScript dodaj następujące zdarzenie
Musimy powiązać funkcję pasteCallBack, ponieważ obserwator mutacji zostanie wywołany asynchronicznie.
krok 3
Dodaj następującą funkcję do swojego kodu
Co robi kod:
Przykład
Pokaż fragment kodu
Wielkie dzięki dla Tim Down Zobacz ten post za odpowiedź:
Pobierz wklejoną treść w dokumencie podczas wklejania zdarzenia
źródło
Rozwiązaniem, które działa dla mnie, jest dodanie detektora zdarzeń w celu wklejenia zdarzenia, jeśli wklejasz tekst. Ponieważ zdarzenie wklejania zdarza się przed zmianą tekstu w danych wejściowych, w moim module obsługi wklejania tworzę odroczoną funkcję, w której sprawdzam zmiany w polu wprowadzania, które nastąpiły podczas wklejania:
źródło
To było zbyt długie, aby skomentować odpowiedź Nica, która, jak sądzę, nie działa już w Firefoksie (w przypadku komentarzy) i nie działała dla mnie w Safari w obecnej postaci.
Po pierwsze, wydaje się, że możesz teraz czytać bezpośrednio ze schowka. Zamiast kodu, takiego jak:
posługiwać się:
ponieważ Firefox ma
types
pole,DOMStringList
które nie jest implementowanetest
.Następny Firefox nie zezwoli na wklejanie, chyba że fokus znajduje się w
contenteditable=true
polu.Wreszcie Firefox nie zezwoli na niezawodne wklejanie, chyba że fokus jest ustawiony na
textarea
(lub być może danych wejściowych), który jest nie tylko,contenteditable=true
ale także:display:none
visibility:hidden
Próbowałem ukryć pole tekstowe, aby umożliwić pracę wklejania na emulatorze JS VNC (tzn. Chodziło do zdalnego klienta i nie było w rzeczywistości
textarea
itp. Do wklejenia). Odkryłem, że próba ukrycia powyższego pola tekstowego dawała symptomy tam, gdzie czasami działała, ale zwykle nie udawało się przy drugim wklejaniu (lub gdy pole zostało wyczyszczone, aby zapobiec dwukrotnemu wklejeniu tych samych danych), ponieważ pole straciło fokus i nie odzyskało prawidłowo pomimofocus()
. Rozwiązaniem, które wymyśliłem, było umieszczenie goz-order: -1000
, zrobienie godisplay:none
, ustawienie jako 1 na 1 piksel i ustawienie wszystkich kolorów na przezroczyste. FujW Safari obowiązuje druga część powyższego, tzn. Musisz mieć taką,
textarea
która nie jestdisplay:none
.źródło
Najpierw przychodzi mi na myśl narzędzie do wklejania biblioteki zamknięcia Google http://closure-library.googlecode.com/svn/trunk/closure/goog/demos/pastehandler.html
źródło
Proste rozwiązanie:
źródło
To działało dla mnie:
źródło
źródło
Możesz to zrobić w ten sposób:
użyj tej wtyczki jQuery do zdarzeń przed i po wklejeniu:
Teraz możesz użyć tej wtyczki ;:
Wyjaśnienie
Najpierw ustaw identyfikator użytkownika dla wszystkich istniejących elementów jako atrybut danych.
Następnie porównaj wszystkie zdarzenia POST PASTE. Porównując, możesz więc zidentyfikować nowo wstawiony, ponieważ będzie on miał identyfikator UID, a następnie po prostu usuń atrybut style / class / id z nowo tworzonych elementów, aby zachować starsze formatowanie.
źródło
źródło
Po prostu pozwól przeglądarce wkleić się jak zwykle w edytowalnym pliku div, a następnie po wklejeniu zamień dowolne elementy zakresu używane w niestandardowych stylach tekstu na sam tekst. Wygląda na to, że działa dobrze w przeglądarce Internet Explorer i innych przeglądarkach, których próbowałem ...
To rozwiązanie zakłada, że korzystasz z jQuery i że nie chcesz formatowania tekstu w żadnym z edytowanych treści div .
Plusem jest to, że jest to bardzo proste.
źródło
span
tagować? Wyobrażam sobie, że pytanie dotyczy wszystkich tagów.To rozwiązanie zastępuje znacznik html, jest proste i działa w wielu przeglądarkach; sprawdź to jsfiddle: http://jsfiddle.net/tomwan/cbp1u2cx/1/ , kod podstawowy:
Uwaga: powinieneś popracować nad filtrem xss z tyłu, ponieważ to rozwiązanie nie może filtrować ciągów takich jak „<< >>”
źródło
To jest istniejący kod opublikowany powyżej, ale zaktualizowałem go dla IE, błąd polegał na tym, że istniejący tekst został zaznaczony i wklejony nie spowoduje usunięcia wybranej zawartości. Zostało to naprawione przez poniższy kod
Zobacz pełny kod poniżej
źródło