• Content assist для элемента textarea

    Очередной эксперимент в поисках идеального средства для простого и быстрого написания кода.

    <textarea>, да и веб-технологии в целом привлекают меня своей простотой, доступностью и возможностью сделать так, как нужно мне. Есть Zen Coding, который позволяет быстро и удобно работать с большим объёмом XHTML-данных, но для пущего удобства не хватает автодополнения кода. Поиск в интернете не дал никаких вменяемых результатов, поэтому решил написать свой:

    content-assist

    Проверить автодополнение можно на тестовой странице. Попробуйте написать несколько английских слов, начинающихся на «a» (awesome, animal, amazing). Должно работать везде, включая IE6.

    Само по себе автодополнение, по большому счёту, практически бесполезно: непонятно, в какой момент какие данные нужно показывать. Поэтому решение представляет из себя несколько отдельных классов, каждый из которых можно переопределить, расширить и дополнить. За основу была взята архитектура автодополнения для Eclipse IDE, поэтому ряд классов и методов называются одинаково.

    • TextViewer — по сути, обёртка для <textarea>. Основное предназначение: дать удобный интерфейс для получения содержимого элемента. Один из основных методов — getCharacterCoords(char_ix), возвращает координаты для определённого символа. Метод возвращает объект со свойствами x и y в пикселях, отсчёт идёт от левого верхнего угла <textarea> до левого верхнего угла нужного символа. Метод getAbsoluteCharacterCoords(char_ix) возвращает то же самое, только относительно offsetParent. Как не трудно догадаться, этот класс можно переписать для работы с content-editable блоком, и у вас будет автодополнение для более серьёзного редактора.
    • ContentAssistProcessor — процессор, который высчитывает и предлагает список дополнений. По умолчанию ищет левую и правую границу английского слова (см. метод isAllowedChar), ищет префикс (от левой границы слова до каретки) и предлагет по этому префиксу список дополнений.
    • CompletionProposal — предложение для автодополнения. Главный метод — apply(), который применяет текущее предложение к TextViewer-объекту.
    • ContentAssist — основной класс. Связывает между собой TextViewer и ContentAssistProcessor, а также управляет всплывающим окном с подсказками.
    • tx_utils — набор всяких DOM-утилит.

    Для добавления поддержки автодополнения для <textarea> нужно инициализировать все эти классы:

    var viewer = new TextViewer(document.getElementById('my-textarea'));
    var processor = new ContentAssistProcessor(['word1', 'word2', 'word3']);
    var content_assist = new ContentAssist(viewer, processor);
    

    Для удобства есть класс BasicContentAssist, который делает всё то же самое для простых случаев (автодополнение по фиксированному словарю):

    new BasicContentAssist(document.getElementById('my-textarea'), ['word1', 'word2', 'word3']);
    

    У класса ContentAssistProcessor есть метод completitionProposalFactory, который должен возвращать объект класса CompletionProposal. Внешний вид попапа с предложениями был нагло позаимствован из редактора Espresso и полностью управляется через CSS. Окошко с предложениями можно вызвать принудительно по Ctrl+Space (не работает в Опере и немного тупит в Файерфоксе) либо по Alt+Space (хвала разработчикам Оперы: это тоже не работает, по крайней мере на Маке) и заменить текущее слово (зависит от позиции каретки).

    Как видите, все классы можно удобно перекрывать, расширять и наследовать для достижения необходимого функционала. Баги, предложения и улучшения принимаются в комментариях и на странице проекта.

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

    Метки: ,
  • 34 комментария

    1. Саша Гольмаков
      14 июня 2010

      Попытка потянуть за скролл в вариантах дополнения у меня стабильно крешит 5 сафари.

    2. explicitcall
      14 июня 2010

      Chrome 5 тоже крашится при перетягивании скролла в вариантах дополнения. Похоже, что это общая проблема у вебкитовских браузеров.

    3. 14 июня 2010

      ну круто. Даже на флэше такого еще не видал

    4. Сергей Чикуенок
      14 июня 2010

      Попробуйте сейчас потаскать, не должен крэшиться

    5. Стас
      14 июня 2010

      Да, риальне очень круто.

    6. 14 июня 2010

      Ого! Крутая штука! Напиши автору akshell.com, наверняка ему понравится.
      И неплохо бы сделать jQuery-плагином, кстати 😉

      P.S. ЕМНИП, в Опере на Маке событие по ctrl срабатывает по cmd.

    7. 15 июня 2010

      Очень круто!
      Жду мануала «How to create predefined dictionary for assist» 🙂

    8. Сергей Чикуенок
      15 июня 2010

      Жду мануала “How to create predefined dictionary for assist”

      То есть мануал «как создать массив слов»?

    9. 15 июня 2010

      нажатие кнопки вниз и _удерживание_ должно запускать прокрутку. удобнее будет
      а фишка удобная

    10. 15 июня 2010

      Сергей, вы в очередной раз меня удивили и порадовали прекрасной разработкой. Уже внедрил в один из своих проектов. По какой лицензии распространяете?

    11. Сергей Чикуенок
      15 июня 2010

      Лицензия MIT

    12. 16 июня 2010

      Спасибо

    13. 16 июня 2010

      Спасибо! Обязательно заюзаю в своем проекте.

    14. 16 июня 2010

      Пардон, про массив ступил, сейчас уже все понятно.
      Единственное что не очень логично — регистрозависимость…

    15. Сергей Чикуенок
      16 июня 2010

      Немного дотюнил процессор, теперь он находит границы слов вне зависимости от языка (то есть можно отдавать словарь с русскими словами), а также немного улучшил поддержку больших словарей. А также добавил в демку пример с <input type="text">

    16. Сергей Чикуенок
      16 июня 2010

      С регистрозависимостью всё не так просто. Например, я могу набирать слово «amazing» как Amazing, AMAZING или AmAZing и в зависимости от префикса нужно делать автодополнение. Для этих целей я и разбил весь проект на несколько классов, чтобы можно было допилить до нужного функционала.

    17. 16 июня 2010

      как же мне надоели эти jQueryкодеры (пренебрежительно). Ну на фига на всякую полезность писать «И неплохо бы сделать jQuery-плагином»
      Зачем? Что не даёт вам пользоватся скриптом втом виде в каком он есть сейчас?
      вот вам плагин

      jQuery.fn.content_assit = function(words) {
      return this.each(function(){
      new BasicContentAssist(this, words)
      });
      };

      использовать так

      $("selector").content_assit(['word1', 'word2', 'word3']);

      Григорий я надеюсь теперь вам стало легче? можете добавлять на http://plugins.jquery.com/

    18. Ви
      18 июня 2010

      Немножко оффтопика (tx_utils.js):


      createElement: function(name, class_name) {
      var elem = document.createElement('div');
      if (class_name)
      elem.className = class_name;

      return elem;
      }

      аттрибут name не используется ;)

    19. 18 июня 2010

      А кто скажет поподробней про BasicContentAssist…

    20. Сергей Чикуенок
      18 июня 2010

      Ви, спасибо, поправлю.
      CTAC9H, а что там рассказывать? Это простая обёртка, которая инициализирует три объект и связывает их между собой. Удобно использовать в случае, если у вас фиксированный словарь дополнений. Если словарь нужно высчитывать динамически либо список дополнений должен зависеть от контекста, то нужно написать свой ContentAssistProcessor и инициализировать автодополнение по образу и подобию BasicContentAssist

    21. 18 июня 2010

      This is so awesome!!!

    22. 111
      18 июня 2010

      Много глюков в IE7: прокрутка показывается не сразу, после выбора значения в попапе перепрыгивает не на конец слова, попап не переносится на новую строку при вводе символа в конце строки. Во всех браузерах: попап начинает съезжать при увеличении/уменьшении размера шрифта, при выборе слова при наличии скрола у textarea перепрыгивает в начало текста.

    23. 18 июня 2010

      похоже координаты коретки в textarea неправильно вычисляются http://img.skitch.com/20100618-p4jutegamritnp635mcq249wwu.png (safari5)

    24. Miki
      6 июля 2010

      http://img10.imageshack.us/img10/7937/contentassist.jpg
      с координатами явно проблемы!!!

    25. Сергей Чикуенок
      6 июля 2010

      Были такие проблемы, но я их вроде исправлял. У вас не могло ничего закэшироваться?

    26. 7 июля 2010

      В ИЕ6 не работает вставка выбранного значения по энтеру. То есть когда всплывает список с вариантами — приходится браться за мышку, чтобы кликнуть на нужное значение. Мне кажется нужно либо вообще забить на ИЕ6, либо уж тогда полностью там все отладить.

    27. 7 июля 2010

      Добрый день!
      1. Наверное слишком мудрено, но если бы можно было сделать поддержку атрибутов при вводе тегов. Что-то на подобии помощника в Dreamweaver. Это возможно/планируется?
      2. Когда в список слов вставляю » — ничего не срабатывает. Без угловых скобок — работает.

    28. Сергей Чикуенок
      7 июля 2010

      Наверное слишком мудрено, но если бы можно было сделать поддержку атрибутов при вводе тегов. Что-то на подобии помощника в Dreamweaver. Это возможно/планируется?

      Да, планируется, но как отдельный подпроект. Смысл написанного — предоставить фрэймворк, из которого можно делать свой content assist. Сейчас пока застопорился в выборе движка для лексического анализа.

    29. 7 июля 2010

      Повторю предыдущее собещение — в переменную для слов вставляю <txp:article /> — с угловыми скобками вообще не работает выпадающее меню

    30. Сергей Чикуенок
      7 июля 2010
    31. zema
      30 августа 2010

      Что-то типа такого можно посмотреть в гугловском RichTextSpeelChecker.
      http://closure-library.googlecode.com/svn/trunk/closure/goog/demos/richtextspellchecker.html
      Там правда не совсем то, что у тебя, но допиливанием можно привести к какому-нить общему знаменателю.

    32. Владимир Игнатьев
      8 декабря 2010

      http://youtrack.jetbrains.net/ — в тему топика. Но как я понимаю, там реализация замера проще, т.к. используется моноширинный шрифт.

      по поводу лексического анализатора могу предложить использовать вообще бэкэнд для этого, на котором лежит длинно-частотный словарь. Можно сделать простейшее обучение для него. У меня есть SQL база со всеми словоформами русского языка. Было бы очень интересно развивать проект.

    33. Антон
      30 августа 2011

      Хммм, странно видеть свой дизайн от чужих людей…
      Год назад рисовал для одного театра http://s46.radikal.ru/i113/1108/59/601f0cd2b958.jpg (вариант принят не был).

    34. Антон
      30 августа 2011

      Промазал комментом, сорри. Это было к http://chikuyonok.ru/2011/08/optimize-with-canvas/