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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> 4 пробела для Python-а (продолжение) +баги Opera8+, сдвиг строк вправо-влево в textarea 
:(
    Опции темы
12345c
Дата 2.12.2006, 20:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Круглый
****


Профиль
Группа: Vingrad developer
Сообщений: 2018
Регистрация: 26.12.2005
Где: наша не пропадала ?

Репутация: 57
Всего: 101



Заведённая довольно давно скромная тема ("вставка/удаление 4-х пробелов при нажатии "Ctrl+]"/"Ctrl+[" " 
) по вставке пробелов-отступов для программ богата на раскрывание особенностей работы с браузерами в textarea. Она такой ожидалась. Уже тема "сборной солянки" (BB-коды, текст над курсором) говорила об этом. И здесь, доработка скрипта, основные усилия в котором легли на обход багов IE, показала незначительные, но баги (один) в Опере 8.01. Конкретно - ну никак не хотела она ставить selectionEnd на место selectionStart, несмотря на то, что обратное работало. Пришлось даже применить TextRange, чтобы превратить выделение в курсор.

Потом, у Оперы есть свойство, что не может установить selectionEnd  со значением, меньшим selectionStart. Если такое происходит, смена выделения самостоятельно отменяется сразу после выполнения скрипта (но не во время выполнения).

Итак, скрипт, который большими усилиями удалось заставить корректно работать в IE, дополнен до поддержки остальных браузеров. Алгоритм гибридизирован, выполняется одной веткой.  Включает в себя функцию lenTR(,) корректного определения длины выделения в IE и комментарии алгоритма.

Код

lenTR=function(oTR,oTa){var ltr; //длина объекта TextRange oTR в области Textarea oTa (IE only)
//Правильно обрабатывает 2 особенности (бага) работы IE
//  - с последними переносами строк в выделении текста и 
//  с выделением последних переносов в конце области textarea
  var tR=document.body.createTextRange();  tR.moveToElementText(oTa);
  var tR1=tR.duplicate();  tR1.setEndPoint('StartToEnd',oTR);
  var tR2=tR.duplicate();  tR2.setEndPoint('StartToStart',oTR);
  var lenSel=tR2.text.length-tR1.text.length;
  if(tR1.text.length>0||oTa.value.length<=tR.text.length)return lenSel;
  else{
    var lenCorr=0;
    var lenCorr2=0;
    var tR3=oTR.duplicate();
    var i,i0;  i=i0=tR3.text.length;
    while(i>=i0&&tR1.text.length==0){
      if(i==0){tR3.moveStart('character',-1);lenCorr--;lenCorr2=1;}
      tR3.moveEnd('character',-1);
      i=tR3.text.length;
      tR1.setEndPoint('StartToEnd',tR3);
      lenCorr++; //чис. переносов строки в конце textarea
  };return lenSel+(lenCorr+lenCorr2-1)*2;}
}

TextAreaSelectionHelper=function(){;} //"класс" приспособлен для демонстрации, поэтому он пустой

TextAreaSelectionHelper.prototype.move4p=function(i){
//====Вставка/удаление 4 пробелов в начале каждой строки выделенной области поля ввода====
//Текст поля ввода разделяется на 3 области:
//1) от начала поля ввода до символа после переноса строки на строке,
//  где начинается выделение или стоит курсор (помещается в строку "а");
//2) выделение (строка "b");
//3) после выделения (строка "с").
//Но при этом концом выделения считается:
//  a) если выделение захватило последний перенос строки,
//    он не включается в выделение;
//  б) если при удалении пробелов (сдвиг текста влево) конец выделения
//    или курсор находится среди начальных пробелов строки, он устанавливается
//    в такое место, чтобы после удаления оказался в начале строки (начальных
//    пробелов может быть сколько угодно, но удаляются до 4 
//    (до 1-го непробельного символа или 4)).
//Далее, в области "b" добавляется по 4 пробела в начале её и после каждого
//  переноса строки или удаляется до 4 пробелов в начале и после каждого переноса строки.
//Используется функция lenTR(oTR,oTa), корректно определяющая длину области TextRange в textarea.
  var d=document;
  var isIE=d.all&&!self.opera;
  if(isIE)this.iesel=d.selection.createRange(); // ***строка для отладки, в рабочем коде находится в другом месте***
  if(isIE&&this.iesel&&this.iesel.parentElement()==this.target    ||this.target.selectionStart>=0&&this.target.selectionEnd>=this.target.selectionStart){
    var RN=(d.all?'\r':'')+'\n';
    if(isIE){var tR1=this.iesel.duplicate();
      tR1.moveToElementText(this.target);
    tR1.setEndPoint('EndToStart',this.iesel);}
    this.ieStart=isIE?lenTR(tR1,this.target):this.target.selectionStart;
    this.ieEnd=isIE?this.ieStart+lenTR(this.iesel,this.target):this.target.selectionEnd;
  var ttv=this.target.value;
    var posLastStr=ttv.substr(0,this.ieStart).lastIndexOf(RN); //алгоритмическая часть
    if(posLastStr<0)posLastStr++;else posLastStr+=RN.length;
    var wasEndRn=0; //был ли конец выделения в конце строки
    if(ttv.charAt(this.ieEnd-RN.length)==RN.charAt(0)&&this.ieStart<this.ieEnd){this.ieEnd-=RN.length;wasEndRn=1;}
    var j=this.ieEnd; //Для удаления пробелов в последней строке - поиск группы, которая будет удалена
    var k=0;
    while(i==0&&ttv.charAt(j)==' '){
      j--;
      if(j==-1||ttv.charAt(j)=='\n'){
        for(k=1;k<=4;k++)if(ttv.charAt(j+k)!=' ')break;
        j+=k;
        break;
    }};if(k>0)this.ieEnd=j;
    var a=ttv.substring(0,posLastStr);
    var b=ttv.substring(posLastStr,this.ieEnd);
    var c=ttv.substr(this.ieEnd);
    var a1,s2,a2;
    var RNg=new RegExp(RN,'g');
    var nRn1=(a1=ttv.substring(0,this.ieStart).match(RNg))?a1.length:0; //для коррекции длины символов переносов в IE
    var nRn2=(a1=b.match(RNg))?a1.length:0;
    var nnp=b.match(/^ {0,4}/)[0].length; //число начальных пробелов
    this.target.value=a+(s2=(i?"    "+b.replace(RNg,RN+"    ")
        :b.replace(new RegExp(RN+'( {1,4}|\t)','g'),RN).replace(/^ {1,4}/,"")))+c;
    a1=this.ieStart+(i?(ttv.substring(posLastStr,this.ieStart+1).replace(/ /g,"")!=""?4:0)
      :-Math.min(Math.max(this.ieStart-posLastStr,0),nnp));
    a2=this.ieEnd+(i?4*nRn2+4:-(b.length-s2.length))+wasEndRn;
    if(isIE){ //установка нового выделения. Сохранить прежнее не представляется возможным по причине багов
      //  в некоторых случаях, а для установки нового нужна небольшая символическая задержка.
      setTimeout("var t=document.getElementById('Post_area').createTextRange();t.collapse();t.moveEnd('character',"
      +(a2-nRn1-nRn2)+");t.moveStart('character',"+(a1-nRn1)+");t.select();",1);
    }else{  this.start=this.target.selectionStart=a1;
      if(this.ieStart==this.ieEnd&&i==0&&self.opera){ //обход бага Оперы с установкой курсора
        var t=document.selection.createRange();t.collapse();t.select();}
      else this.end=this.target.selectionEnd=a2;   
    }
}
if(!isIE){
if(this.scroll&&this.scroll>=0)this.target.scrollTop=this.scroll;
this.target.focus();}
}

Демонстрирующий код (так как он написан к функции, в нём есть избыточность вызовов по событиям) :
Код

<script>d=document //пример для демонстрации вставки-удаления 4 пробелов в начале строк
f1=new TextAreaSelectionHelper();
onload=function(){f1.target=d.getElementById('Post_area');}
</script>
<input type=button value="Ctrl+[" onmousedown=if(d.all)f1.move4p(1) onmouseup=if(!d.all)f1.move4p(1)> <input type=button value="Ctrl+]" onmousedown=if(d.all)f1.move4p(0) onmouseup=if(!d.all)f1.move4p(0)> <br>
<!-- 4 вызова по событиям - для приспособления демонстрационного примера к функции move4p()-->
<textarea cols=70 rows=20 id=Post_area>fdsF
  dsf
  
  f
  sf
f

f
dsf
ds
fd
sg
f
dg

ffff пример заполненного поля




g
f
g
fd
g
f
g
f
h
gfh
gf
h

</textarea>
Для тестирования имеют значение выделения текста с переносами строк в конце. Обычно баг IE не позволяет их обрабатывать. Выделите текст так, чтобы в конце выделения были переносы строк и проверяйте. В других случаях тестирования, я, например, нашёл 2 алгоритмических недочёта smile. Но если никто их не найдёт, значит, всех устроит.

Если всё устроит, сделанную функцию можно внедрять в форум. Пример внедрённой функции лежит в архиве http://js2.ru/files/vingradScripts.rar (30К). Там же, кстати, и приведённый выше код в 1 файле.

Длины функций кода.Как видно, для реализации корректной работы надо необычно много кода. Кроме того, что сама алгоритмическая часть занимает 50-60% функции move4p, есть ещё функция специально для исправления багов IE, других способов обхода которого практически нет. Суммарная длина кода без комментариев и демо-примера - 2700 байт.

Проверялся только под Win (IE6, 7, FF1.07, 2, Opera8.01), поэтому настоятельная просьба проверить под Юниксом и в Сафари - скорее всего, придётся что-то дорабатывать (для Сафари).

Дополнение по теме багов: По чудесам выделения текстов в IE есть такой пример:http://js2.ru/example/JsPrimeryCode-97.htm - "IE-ошибки определения длины областей TextRange в Textarea".

Дополнение по клавишному управлению на Винграде: посмотрел работу скриптов клавишного управления на Винграде и в примере, который я из него вырезал  - оказывается, кнопочное управление для IE на нём работает очень плохо - в чистом IE6 срабатывают немногие кнопки. Должны работать все, которые описаны в HotKeyHandler.keys и HotKeyHandler.alt_keys (ToolMenuData.js), но работают в чистом IE6 только Ctrl-U, Q, остальные, видимо, перебиваются браузерными функциями. В остальных браузерах клавиши работают нормально, в том числе и внедрённые мной коды Ctrl+[, Ctrl+] .

Это сообщение отредактировал(а) 12345c - 3.3.2008, 13:15


--------------------
Google Code Playground - онлайн-отладка своих примеров HTML+JS без регистрации, с сохранением по URL, без кириллицы. Go
PM WWW   Вверх
Sardar
Дата 4.12.2006, 01:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 78
Всего: 317



Цитата(12345c @  2.12.2006,  19:55 Найти цитируемый пост)
посмотрел работу скриптов клавишного управления на Винграде и в примере...

Ух-ты... Это я писал и проверял под всеми популярными браузерами (FireFox1.4+ , IE5.5+, Opera6+, Konqueror), работало всё корректно. Не надо думаю объяснять, что тестя все четыре браузера автоматом тестим все подобные на таких же движках (Seamonkey, MyIE, Safari etc). Покопаюсь в последних переделках...

По коду, вижу бага с обрезанием переносов только для индента убрана... ожидал что если и будешь править, то для всех функций. Вместо архива лучше дал бы ссылку. Если считаешь, что код уже готов, поставлю на SVN, от туда на форум.

P.S. млин не читабельно пишешь...


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
12345c
Дата 4.12.2006, 02:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Круглый
****


Профиль
Группа: Vingrad developer
Сообщений: 2018
Регистрация: 26.12.2005
Где: наша не пропадала ?

Репутация: 57
Всего: 101



Цитата(Sardar @  4.12.2006,  01:36 Найти цитируемый пост)
Не надо думаю объяснять, что тестя все четыре браузера автоматом тестим все подобные на таких же движках (Seamonkey, MyIE, Safari etc). 
Насчёт оболочек - не совсем так. В MyIE и других добавляются новые клавишные функции, которые могут перебивать события чистой оболочки. Haпример, Сtrl+I в Макстоне - открывание боковой панели (Explorer Bar). В IE это Favorities -панель, но неизвестно, кто перехватывает раньше.

Править TextAreaSelectionHelper.prototype.setSelectedText для всех остальных функций - это заново переписать, добавив примерно 1-1.5 К кода. Тут стоит вопрос, что 2.5 К на "4 пробела" много... Скажут админы: "Поставим" - сделаю по аналогии, мне будет проще, чем тебе вдаваться во все детали.

Добавлено @ 02:14 
Что код готов, должны сказать тестеры. Мне - так 2 момента не нравится в алгоритме, и в Сафари никто не проверял и там будут ошибки (если переносы - это \r).
PM WWW   Вверх
12345c
Дата 11.1.2007, 14:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Круглый
****


Профиль
Группа: Vingrad developer
Сообщений: 2018
Регистрация: 26.12.2005
Где: наша не пропадала ?

Репутация: 57
Всего: 101





Тем временем обнаружил код с недокументированной функцией вставки-убирания табов в начале каждой строки выделенной области - http://www.artlebedev.ru/tools/technogrett.../allow_tab_key/ . Если выделить область начала строки, одну или несколько, то нажатие Tab приведёт к вставке табов, а нажатие Shift-Tab - к удалению табов (по одному) в начало / из начала каждой строки. (Захват пустых переносов в конце выделения, как обычно, крупно пролетает в IE, так что значимости написанного кода не умаляет, но интересен принцип реализации - достаточно простая функция вставки-удаления. Конечно, тут не надо ловить пробелы, не кратные 4, что упрощает выполнение, но и нет заморочек с принудительным выделением строки, если нажато "Ctrl-[" .)

Это сообщение отредактировал(а) 12345c - 11.1.2007, 14:43
PM WWW   Вверх
Sardar
Дата 11.1.2007, 22:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бегун
****


Профиль
Группа: Модератор
Сообщений: 6986
Регистрация: 19.4.2002
Где: Нидерланды, Groni ngen

Репутация: 78
Всего: 317





У нас задача была несколько иная, с любой позиции в строке сдвинуть строку, что и изменило/усложнило реализацию smile


--------------------
 Опыт - сын ошибок трудных  © А. С. Пушкин
 Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik
 Оценить мои качества можно тут.
PM   Вверх
Girder
Дата 13.1.2007, 12:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй 2
***


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

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





Цитата(Sardar @  4.12.2006,  01:36 Найти цитируемый пост)
Ух-ты... Это я писал и проверял под всеми популярными браузерами (FireFox1.4+ , IE5.5+, Opera6+, Konqueror), работало всё корректно.
Естественно - но только когда было повешенно на Body smile , а по просьбе трудящийся теперь только на тектовом поле.



--------------------
Как слышим, так и пишим.
Истина где-то там...
PM   Вверх
pythonwin
Дата 15.1.2007, 07:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



12345cSardarGirder, спасибо, что работаете над проблемой и делаете наш форум лучше smile
PM WWW GTalk Jabber   Вверх
V.A.KeRneL
  Дата 3.3.2007, 15:37 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Vadim A. Kazantsev
**


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

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



По совету pythonwin тоже говорю здесь всем спасибо! smile



--------------------
«C'est un pense-creux d'ici. C'est le meilleur et le plus irascible homme du monde...» © Ф.М. Достоевский, «Бесы»
---/)/)---(\.../)---(\(\
--(':'=)---(=';'=)---(=':')
(")(")..)-(").--.(")-(..(")(")

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


 




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


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

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