Модераторы: Sardar, Aliance
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Перехват и обработка события onpaste в DesignMode, Требуется вставить буфер как plain text 
:(
    Опции темы
Stampede
Дата 12.4.2011, 18:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 4
Всего: 144



Всем привет!

Взываю к коллективной мудрости. Есть следующая задача.

Я приделываю к своему сайту визуальный редактор NicEdit. Выбрал его за компактность, простоту и разборчивый код. Вроде пока все получается, хотя многое приходится затачивать под свои нужды. Сейчас встал вопрос о том, чтобы при копированиии в поле редактирования содержимое буфера очищалось от разметки HTML.

В ходе продолжительных поисков и экспериментов наткнулся вот на такую подсказку: 

Цитата
What you can do is quite involved and a bit of a hack that will work in Firefox 2+, IE 5.5+ and recent WebKit browsers such as Safari 4 or Chrome (untested on older versions). Recent versions of both TinyMCE and CKEditor use this technique:

   1. Detect a ctrl-v / shift-ins event using a keypress event handler
   2. In that handler, save the current user selection, add a textarea element off-screen (say at left -1000px) to the document, turn designMode off and call focus() on the textarea, thus moving the caret and effectively redirecting the paste
   3. Set a very brief timer (say 1 millisecond) in the event handler to call another function that stores the textarea value, removes the textarea from the document, turns designMode back on, restores the user selection and pastes the text in.

Note that this will only work for keyboard paste events and not pastes from the context or edit menus. By the time the paste event fires, it's too late to redirect the caret into the textarea (in some browsers, at least).

Ссылка: http://stackoverflow.com/questions/2176861...t-cross-browser


Закодил согласно описанию, получилось вот так:



Остается одна маленькая досадная мелочь: если вклеивать содержимое буфера через меню или перетаскиванием, то "очистительный фильтр", естественно, не срабатывает. Кто подскажет, что здесь можно сделать?

Для удобства привожу полный код страницы:

Код

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<head>
    <title>Test: Paste as plain text</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<style type="text/css">
* {
    margin: 0px;
    padding: 0px;
}

body {
    width: 400px;
    margin: 0px auto;
}

#form {
    margin: 1em 0px;
}

#pane {
    height: 200px;
    border: 1px solid silver;
}

#area {
/*
position: fixed;
left: -999px;
*/
    width: 400px;
}
</style>

<script type="text/javascript" language="javascript">
// http://stackoverflow.com/questions/2176861/javascript-get-clipboard-data-on-paste-event-cross-browser
var pane;
var form;
var doc;
var area;

function init() {
    form = document.getElementById('form');
    pane = document.getElementById('pane');
    pane.onkeydown = test_paste;

    area = document.getElementById('area');
}

function test_paste(evt) {
    evt = evt || window.event;

    var code = (evt.charCode)?
        evt.charCode : ((evt.which)? evt.which : evt.keyCode);


    if ((evt.ctrlKey && code == 86) || (evt.shiftKey && code == 45)) {
        do_paste();
    }
}

var currange;
var cursel;
function do_paste() {
    var sel;
    if (document.all) { // IE
        cursel = document.selection;
        currange = (cursel)? cursel.createRange() : null;
    }
    else {
        cursel = (window.getSelection || document.getSelection) ();
        currange = (cursel)? cursel.getRangeAt(0) : null;
    }

    area.value = '';
    area.focus();
    setTimeout(finish_paste, 1);
}

function finish_paste() {
    if (document.all) {
        area.select();
        pane.focus();
        currange.pasteHTML(area.value);
    }
    else {
        cursel.removeAllRanges();
        cursel.addRange(currange);
        pane.focus();
        document.execCommand('insertHTML', false, area.value);
    }
}

</script>

</head>

<body onload="init();">

<form id="form">
    <div id="pane" contentEditable></div>
</form>

<textarea id="area"></textarea>

<p id="lorem"><b>Lorem Ipsum</b> is simply <i>dummy text</i> of the printing and <u>typesetting industry</u>. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>

</body>

</html>


Заранее спасибо!


--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
ksnk
Дата 12.4.2011, 19:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 84
Всего: 386



Можно перехватывать событие onpaste и сохранять контент в переменной. После небольшого таймаута можно выковырять изменения в контенте простым текстовым сравнением с начала и конца текста с сохраненным значением. 

Правда, вероятно, возможны разные глюки, при вставке некорректного Html, например. При этом броузер будет корректировать контент и сравнение будет глючить.

Возможно, можно выковыривать изменения более разумно, используя сохраненную позицию курсора до вставки и после вставки, хотя с этим надо возится... 


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
Котокобра
Дата 12.4.2011, 21:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 147
Регистрация: 26.11.2009

Репутация: нет
Всего: 4



а что мешает очищать всегда, когда произведена вставка?
PM MAIL   Вверх
Stampede
Дата 12.4.2011, 21:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 4
Всего: 144



Цитата(Котокобра @  12.4.2011,  12:24 Найти цитируемый пост)
а что мешает очищать всегда, когда произведена вставка? 


К содержимому буфера в общем случае не так легко доступиться, поэтому приходится идти на такие вот ухищрения.


--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
Котокобра
Дата 12.4.2011, 22:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 147
Регистрация: 26.11.2009

Репутация: нет
Всего: 4



посмотрел пример. я думаю, текст нужно парсить. что-нибудь в этом духе:

Код

<script>
var str = "<i><b>text</b></i>";

var reg = /<\/{0,1}(b|i)>/ig;

str = str.replace(reg, "");

alert(str);

</script>


PM MAIL   Вверх
Stampede
Дата 13.4.2011, 01:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 4
Всего: 144



Котокобра, загвоздка не в том, чтобы руками вычистить разметку (хотя, конечно, это делается не так прямолинейно, как в вашем примере — вспомним хотя бы, что теги могут быть с атрибутами), а в том, чтобы получить содержимое буфера обмена. Firefox, например, скрывает его от программного доступа из соображений безопасности. Потому-то WYSIWYG-редакторы вынуждены делать финт ушами: позволяют браузеру сделать вставку своим внутренними средствами, но при этом перенаправляют вывод в текстовое поле путем изменения фокуса.

Какие еще будут идеи?



--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
Stampede
Дата 13.4.2011, 01:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 4
Всего: 144



Если другого выхода не будет, тупо поставлю на onpaste заглушку с сообщением, чтобы копировали с клавы. Примерно так, как это сделано в TinyMCE:

user posted image

Но прежде чем капитулировать, хочется все же еще немного повоевать. Так что продолжаем мозговой штурм.


--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
ksnk
Дата 13.4.2011, 08:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 84
Всего: 386



Цитата(Stampede @  13.4.2011,  01:54 Найти цитируемый пост)
Если другого выхода не будет

вобще-то, событие onpaste в Мозиле есть. Убедиться в этом достаточно легко
Код

...

function init() {
    form = document.getElementById('form');
    pane = document.getElementById('pane');
    pane.onkeydown = test_paste;
    pane.onpaste = function (){alert("paste");}; //<<<<<<<<<<<<<<<<<<
    area = document.getElementById('area');
}
...


Цитата(Stampede @  12.4.2011,  21:34 Найти цитируемый пост)
К содержимому буфера в общем случае не так легко доступиться

А в чем проблема? Получить содержимое области редактирования? Получить положение "курсора"?


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
Stampede
Дата 13.4.2011, 08:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 4
Всего: 144



Цитата(ksnk @  12.4.2011,  23:01 Найти цитируемый пост)
вобще-то, событие onpaste в Мозиле есть. Убедиться в этом достаточно легко


Событие-то есть, но нет простой возможности получить содержимое буфера. Скажем, команды cut/copy/paste, выполняемые по document.execCommand, не дают ничего сделать, пока не подредактируешь настройки безопасности в пользовательском файле user.js.

Существуют хаки в виде флэшевых компонентов для работы с буфером (например, ZeroClipboard), но нет никакой гарантии, что в будущем Adobe не прикроет эту лавочку.

Впрочем, как вариант можно и попробовать.

Stay tuned!

Это сообщение отредактировал(а) Stampede - 13.4.2011, 08:26


--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
ksnk
Дата 13.4.2011, 09:45 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 84
Всего: 386



Цитата(Stampede @  13.4.2011,  08:25 Найти цитируемый пост)
Событие-то есть, но нет простой возможности получить содержимое буфера

А зачем нам буфер? Нам нужно получить изменение.

Вот небольшая модификация "рабочего примера" для демонстрации. Из за теперешнего перехвата клавиатурной вставки срабатывает только на вставку из copy-paste менюшки.
Осталось только прикрутить что-то такое на drag&drop. Но, вроде, даже события такие где-то появились...
Код

/** 
 * вызываем по событию onpaste,
 * запоминаем значение во внутренней переменной
 * через небольшой таймаут - сравниваем изменившееся значение и выводим изменение алертом
 */
function clearContent(el){
  var lastHtml=el.innerHTML||'';
  setTimeout(function(){
    var newHtml = el.innerHTML||'';
    var i =0,j,start=0,finish=newHtml.length-1;
    for(i=0;i< lastHtml.length;i++){
        if(lastHtml.charAt(i)!=newHtml.charAt(i)) {
            start=i; 
            break; 
        }
    }
    for(i=lastHtml.length-1,j=newHtml.length-1;i>start;i--,j--){
        if(lastHtml.charAt(i)!=newHtml.charAt(j)) {
            finish=j; 
            break; 
        }
    }
    alert([newHtml.substring(start,finish+1)]); 
  },1);

}

function init() {
    form = document.getElementById('form');
    pane = document.getElementById('pane');
    pane.onkeydown = test_paste;
    pane.onpaste = function (){clearContent(pane);}; // !!!!!!!!!!
    area = document.getElementById('area');
}


Добавлено через 1 минуту и 10 секунд
Я проверяю на FireFox. сейчас, к сожалению, нет возможности проверить на других броузерах. :(


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
Stampede
Дата 13.4.2011, 10:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 4
Всего: 144



ksnk, спасибо за деятельное участие в решении вопроса. Метод не без недостатков (например, при большом объеме вклеиваемого форматированного текста будет заметно видимое перемигивание), но в целом "ход вашей мысли мне нравится" © , так что держите плюса.



--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
Stampede
Дата 13.4.2011, 23:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гносеолог
**


Профиль
Группа: Участник Клуба
Сообщений: 963
Регистрация: 25.4.2005
Где: Calgary, Alberta, Canada

Репутация: 4
Всего: 144



Ну что я могу сказать: вроде бы получилось. Посмотреть и потестить можно вживую:



Код, приведенный ksnk, пришлось подправить в части коррекции маркеров начала и конца расхождения до границ тегов. Это, конечно, далеко не окончательый вариант, но без этого вообще вставлялось с ненужными хвостами.

Ну и перемигивание при вставке, действительно, довольно заметное.

Полный код страницы такой:

Код

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html>

<head>
    <title>Test: Paste as plain text</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<style type="text/css">
* {
    margin: 0px;
    padding: 0px;
}

body {
    width: 400px;
    margin: 0px auto;
}

#form {
    margin: 1em 0px;
}

#pane {
    height: 200px;
    border: 1px solid silver;
}

#area {
/*
position: fixed;
left: -999px;
*/
    width: 400px;
}
</style>

<script type="text/javascript" language="javascript">
// http://stackoverflow.com/questions/2176861/javascript-get-clipboard-data-on-paste-event-cross-browser
var pane;
var form;
var doc;
var area;

function init() {
    form = document.getElementById('form');
    pane = document.getElementById('pane');
    pane.onkeydown = test_paste;
    // pane.onpaste = capture_paste;
    pane.onpaste = function () {clearContent(pane);}; // !!!!!!!!!!

    area = document.getElementById('area');
}

function test_paste(evt) {
    evt = evt || window.event;

    var code = (evt.charCode)?
        evt.charCode : ((evt.which)? evt.which : evt.keyCode);


    if ((evt.ctrlKey && code == 86) || (evt.shiftKey && code == 45)) {
        do_paste();
    }
}

function capture_paste(evt) {
    evt = evt || window.event;

    if (document.all) { // IE
        cursel = document.selection;
        currange = (cursel)? cursel.createRange() : null;
        area.value = window.clipboardData.getData('Text');
    }
    else {
        cursel = (window.getSelection || document.getSelection) ();
        currange = (cursel)? cursel.getRangeAt(0) : null;
        area.value = '';
    }
    finish_paste();

    evt.cancelBubble = true;
    return false;
}

var currange;
var cursel;
function do_paste() {
    if (document.all) { // IE
        cursel = document.selection;
        currange = (cursel)? cursel.createRange() : null;
    }
    else {
        cursel = (window.getSelection || document.getSelection) ();
        currange = (cursel)? cursel.getRangeAt(0) : null;
    }

    area.value = '';
    area.focus();
    setTimeout(finish_paste, 1);
}

function finish_paste() {
    if (document.all) {
        area.select();
        pane.focus();
        currange.pasteHTML(area.value);
    }
    else {
        cursel.removeAllRanges();
        cursel.addRange(currange);
        pane.focus();
        document.execCommand('insertHTML', false, area.value);
    }
}

function clearContent(el){
  var _oldHtml=el.innerHTML||'';
  setTimeout(function(){
    var oldHtml = _oldHtml;
    var newHtml = el.innerHTML||'';
    var tagStart = -1;
    var i = 0, j ,start = 0, finish = newHtml.length-1;
    for(i=0;i< oldHtml.length;i++){
     var c = oldHtml.charAt(i);
     var cc = (i < oldHtml.length - 1)? oldHtml.charAt(i + 1) : '';
     if (tagStart < 0 && c == '<' && isAlpha(cc)) {
         tagStart = i;
     }
     else if (tagStart >= 0 && c == '>') {
         tagStart = -1;
     }
        if(oldHtml.charAt(i)!=newHtml.charAt(i)) {
            start = (tagStart >= 0)? tagStart : i;
            break;
        }
    }

    var tagEnd = -1;
    for(i = oldHtml.length - 1, j = newHtml.length-1; i >= 0; i--, j--){
     var c = newHtml.charAt(j);
     if (c == '>') {
         for (var k = j - 1; k >= 0; k--) {
             c = newHtml.charAt(k);
             if (c == '/') {
                 tagEnd = j;
                 break;
             }
             if (!isAlphaNumeric(c)) {
                 tagEnd = -1;
                 break;
             }
         }
     }
     else if (tagEnd > 0 && c == '<') {
          tagEnd = -1;
     }
        if(oldHtml.charAt(i)!=newHtml.charAt(j)) {
            finish = (tagEnd > 0)? tagEnd + 1 : j;
            break;
        }
    }
    var diff = newHtml.substring(start, finish);
    diff = stripHtml(diff);
    // alert(diff);
    el.innerHTML = newHtml.substring(0, start) + diff + newHtml.substring(finish);
  },1);
}

function stripHtml(str) {
   var tmp = document.createElement("DIV");
   tmp.innerHTML = str;
   return tmp.textContent||tmp.innerText;
}

function isAlpha(s) {
    return /^[a-z]+$/i.test(s);
}

function isNumeric(s) {
    return /^[0-9]+$/.test(s);
}

function isAlphaNumeric(s) {
    return /^[a-z0-9]+$/i.test(s);
}


</script>

</head>

<body onload="init();">

<form id="form">
    <div id="pane" contentEditable></div>
</form>

<textarea id="area"></textarea>

<p id="lorem"><b>Lorem Ipsum</b> is simply <i>dummy text</i> of the printing and <u>typesetting industry</u>. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>

</body>

</html>


Если у кого-то будут еще какие-либо другие предложения — давайте обсудим.


--------------------
"If you want something done right, do it yourself"
По секрету: выучить английский - реально!
PM WWW   Вверх
Embedded
Дата 28.4.2011, 17:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 65
Регистрация: 22.2.2011
Где: Россия

Репутация: нет
Всего: 1



довольно неплохая штука nicedit, имхо tinymce сильно загружен ненужностямии у tiny какие-то странные глюки при копировании/вставке из ie в opera 

Это сообщение отредактировал(а) Embedded - 29.4.2011, 11:46
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Форум для вопросов, которые имеются в справочниках, но их поиск вызвал затруднения, или для разработчика требуется совет или просьба отыскать ошибку. Напоминаем: 1) чётко формулируйте вопрос, 2) приведите пример того, что уже сделано, 3) укажите явно, нужен работающий пример или подсказка о том, где найти информацию.
 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | JavaScript: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1646 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.